Flutter 프로젝트 뼈대 세우기 🎯 이번 단계에서 배울 것
flutter create
가 만들어 주는 기본 파일과 폴더 구조 파악
.gitignore
, analysis_options.yaml
, pubspec.yaml
등 핵심 설정 파일 역할 이해
Android, iOS, Web, Desktop(Windows·macOS·Linux) 플랫폼별 초기 코드 살펴보기
기본 위젯 테스트 템플릿(test/widget_test.dart
)이 어떤 구조로 생성되는지 확인
📂 파일 구조 1 2 3 4 5 6 7 새로 만들어지는 파일 - .gitignore / .metadata - README.md / analysis_options.yaml - pubspec.yaml / pubspec.lock - android/**, ios/**, linux/**, macos/**, web/**, windows/** 플랫폼 코드 전체 - lib/main.dart (기본 앱 진입점) - test/widget_test.dart (위젯 테스트 템플릿)
📝 1단계: Flutter 프로젝트 생성하기 실행한 명령 (터미널):
🔍 코드 상세 설명 1. 버전 관리 제외 목록(.gitignore)
1 2 3 4 5 6 7 # Flutter/Dart/Pub related **/doc/api/ **/ios/Flutter/.last_build_id .dart_tool/ .flutter-plugins .pub-cache/ .build/
자동 생성·빌드 산출물은 버전 관리에서 제외해 저장소가 가벼워집니다.
플랫폼별 빌드 아티팩트를 올리지 않아 협업 시 충돌을 줄일 수 있습니다.
2. 분석 규칙(analysis_options.yaml)
1 2 3 4 5 include: package:flutter_lints/flutter.yaml linter: rules: avoid_print: false
Flutter 공식 린트 세트를 포함하여 코드 일관성을 유지합니다.
기본 규칙에서 print
허용으로 초반 디버깅을 쉽게 합니다.
3. 프로젝트 메타 정보(pubspec.yaml)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 name: toonflix publish_to: 'none' description: A new Flutter project. environment: sdk: '>=2.18.2 <3.0.0' dependencies: flutter: sdk: flutter cupertino_icons: ^1.0.2 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^2.0.0
패키지 이름과 설명이 프로젝트를 대표합니다.
SDK 범위와 기본 의존성(flutter
, cupertino_icons
)이 명시되었습니다.
테스트와 린트 패키지는 개발 단계에서만 사용됩니다.
4. 플랫폼별 진입 파일 예시
1 2 3 class MainActivity : FlutterActivity () {}
1 2 3 4 5 6 7 8 9 10 11 @UIApplicationMain class AppDelegate : FlutterAppDelegate { override func application ( _ application : UIApplication , didFinishLaunchingWithOptions launchOptions : [UIApplication .LaunchOptionsKey : Any ]? ) -> Bool { GeneratedPluginRegistrant .register(with: self ) return super .application(application, didFinishLaunchingWithOptions: launchOptions) } }
Android는 FlutterActivity
를 상속해 Flutter 엔진을 구동합니다.
iOS는 FlutterAppDelegate
를 확장하여 플러그인 등록 코드를 포함합니다.
비교 예시:
1 2 3 4 5 # Flutter/Dart/Pub related # ← 새 항목 추가 전 (doc/api 등의 빌드 산출물이 추적됨) # Flutter/Dart/Pub related # ← 새 항목 추가 후 .build/ 등이 무시되어 깃 기록이 깔끔해짐
시각화:
1 2 3 4 5 6 7 8 9 10 ┌─ 프로젝트 루트 │ ├─ lib/ → Dart 소스 │ ├─ android/ → Kotlin & Gradle │ ├─ ios/ → Swift & Xcode 설정 │ ├─ macos/ → macOS Runner │ ├─ linux/ → GTK Runner │ ├─ windows/ → Win32 Runner │ ├─ web/ → 웹 정적 자산 │ └─ test/ → 위젯 테스트 기본 템플릿 └──────────────────────────────────────────
🎨 화면 미리보기 1 2 3 4 5 6 터미널 ┌──────────────────────────────────────┐ │ flutter create toonflix │ │ → Running "flutter pub get" │ │ → "toonflix" created successfully. │ └──────────────────────────────────────┘
📊 동작 흐름 1 2 3 4 5 1. flutter create toonflix 실행 2. Flutter SDK가 템플릿 파일 복사 3. pubspec.yaml 기반으로 의존성 다운로드(pub get) 4. 플랫폼별 Runner 프로젝트 생성 5. 기본 테스트 및 분석 설정 파일 생성
✅ 체크리스트
💡 연습 과제
프로젝트 설명 수정: pubspec.yaml
의 description
을 본인 프로젝트 목적에 맞게 수정해보세요.
린트 규칙 추가: analysis_options.yaml
에 prefer_const_constructors
와 같은 규칙을 더해보고 경고 변화를 확인하세요.
플랫폼 빌드 시도: 안드로이드 스튜디오나 Xcode로 Runner 프로젝트를 열어 빌드 과정을 체험해보세요.
Hello World 화면 구성 🎯 이번 단계에서 배울 것
Flutter 앱의 진입점(main()
과 runApp
) 이해
StatelessWidget
, MaterialApp
, Scaffold
의 역할 파악
AppBar
, Center
, Text
위젯으로 기본 UI 구성하기
자동 생성된 위젯 테스트 템플릿이 현재 코드와 어떻게 어긋나는지 확인
📂 파일 구조 1 2 3 4 5 수정되는 파일 - lib/main.dart (커스텀 Hello World UI 구성) 기본 유지 파일 - test/widget_test.dart (Counter 예제 테스트 템플릿)
📝 1단계: Hello World UI 빌드하기 전체 코드 (lib/main.dart):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import 'package:flutter/material.dart' ;void main() { runApp(App()); } class App extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: Text('Hello flutter!' ), ), body: Center( child: Text('Hello world!' ), ), ), ); } }
🔍 코드 상세 설명 1. main()
함수와 runApp
1 2 3 void main() { runApp(App()); }
Dart 애플리케이션의 진입점으로, 앱 실행 시 가장 먼저 호출됩니다.
runApp
은 전달한 위젯(App
)을 위젯 트리의 루트로 등록하고 렌더링을 시작합니다.
2. StatelessWidget
으로 화면 정의
1 2 3 4 5 6 class App extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp(...); } }
상태 변화가 필요 없는 정적인 화면 데이터에 적합합니다.
build
메서드는 UI 트리를 반환하며, Flutter가 이 반환값을 사용해 화면을 그립니다.
3. MaterialApp
과 Scaffold
구조
1 2 3 4 5 6 return MaterialApp( home: Scaffold( appBar: AppBar(title: Text('Hello flutter!' )), body: Center(child: Text('Hello world!' )), ), );
MaterialApp
은 Material Design 스타일의 전역 설정(네비게이션, 테마 등)을 제공합니다.
Scaffold
는 상단 앱바, 본문 영역 등 기본 레이아웃 뼈대를 제공합니다.
4. UI 구성 위젯
1 2 3 4 5 6 appBar: AppBar( title: Text('Hello flutter!' ), ), body: Center( child: Text('Hello world!' ), ),
AppBar
는 화면 제목 영역을, Center
는 자식 위젯을 중앙에 배치합니다.
Text
위젯으로 간단한 문자열을 출력합니다.
비교 예시:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class MyApp extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp( home: MyHomePage(title: 'Flutter Demo Home Page' ), ); } } class App extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: Text('Hello flutter!' )), body: Center(child: Text('Hello world!' )), ), ); } }
시각화:
1 2 3 4 5 6 7 ┌─────────────────────────────┐ │ Hello flutter! [ ] │ AppBar ├─────────────────────────────┤ │ │ │ Hello world! │ Center → Text │ │ └─────────────────────────────┘
🎨 화면 미리보기 1 2 3 4 5 6 위젯 트리 App └── MaterialApp └── Scaffold ├── AppBar → Text('Hello flutter!') └── Center → Text('Hello world!')
📊 동작 흐름 1 2 3 4 5 1. 사용자가 앱을 실행 2. Flutter 엔진이 main()을 호출 3. runApp(App())으로 루트 위젯 등록 4. App.build() → MaterialApp → Scaffold → UI 구성 5. 화면에 Hello World UI 렌더링
✅ 체크리스트
💡 연습 과제
테마 적용: MaterialApp
에 theme: ThemeData(primarySwatch: Colors.blue)
를 추가해 색상을 바꿔보세요.
텍스트 스타일 변경: Text('Hello world!')
에 style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)
를 적용해보세요.
테스트 갱신: test/widget_test.dart
에서 MyApp
대신 App
을 pump하도록 수정해 보고 테스트를 실행해보세요.
자동 생성 테스트 코드 이해하기 🎯 이번 단계에서 배울 것
Flutter가 기본으로 제공하는 위젯 테스트 구조 파악
현재 UI와 테스트 코드의 불일치 원인 분석
WidgetTester를 활용해 상호작용을 검증하는 흐름 이해
📂 파일 구조 1 2 검토할 파일 - test/widget_test.dart
📝 1단계: 기본 테스트 읽어보기 전체 코드 (test/widget_test.dart):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import 'package:flutter/material.dart' ;import 'package:flutter_test/flutter_test.dart' ;import 'package:toonflix/main.dart' ;void main() { testWidgets('Counter increments smoke test' , (WidgetTester tester) async { await tester.pumpWidget(const MyApp()); expect(find.text('0' ), findsOneWidget); expect(find.text('1' ), findsNothing); await tester.tap(find.byIcon(Icons.add)); await tester.pump(); expect(find.text('0' ), findsNothing); expect(find.text('1' ), findsOneWidget); }); }
🔍 코드 상세 설명 1. testWidgets
흐름
pumpWidget
으로 테스트 대상 위젯을 렌더링하고 프레임을 강제로 갱신합니다.
find.text
, find.byIcon
으로 위젯을 검색하고 expect
로 검증합니다.
2. 현재 실패하는 이유
커밋된 실제 코드에는 MyApp
이 존재하지 않고 App
클래스만 있습니다.
Counter 버튼 UI도 삭제되었으므로 '0'
, '1'
, Icons.add
를 찾을 수 없어 테스트가 실패합니다.
비교 예시:
1 2 await tester.pumpWidget(const MyApp()); await tester.pumpWidget(App());
시각화:
1 2 3 4 5 6 7 8 9 10 테스트 기대 UI ┌─ AppBar: "Flutter Demo" ─────────────┐ │ 0 │ │ [+] button │ └──────────────────────────────────────┘ 실제 UI (현재 프로젝트) ┌─ AppBar: "Hello flutter!" ───────────┐ │ Hello world! │ └──────────────────────────────────────┘
🎨 화면 미리보기 1 2 3 테스트 실행 예상 결과 - 기본 코드 유지: green (모든 검증 통과) - 현재 코드 상태: red (위젯 탐색 실패로 AssertionError)
📊 동작 흐름 1 2 3 1. WidgetTester가 MyApp을 렌더링하려 시도 2. MyApp 클래스를 찾지 못해 런타임 오류 발생 또는 3. (MyApp을 만든 후라도) '+' 아이콘과 Counter 텍스트 부재로 expect 실패
✅ 체크리스트
💡 연습 과제
테스트 업데이트: pumpWidget(App())
으로 교체하고, “Hello world!” 텍스트가 존재하는지 검사하도록 테스트를 바꿔보세요.
추가 검증 작성: AppBar 제목이 “Hello flutter!”인지 확인하는 단언문을 추가해보세요.
위젯 찾기 연습: find.byType(AppBar)
등을 사용하여 원하는 위젯을 찾는 방법을 연습해보세요.
📚 전체 흐름 정리
flutter create
명령으로 모든 플랫폼 폴더와 설정 파일이 생성되었습니다.
lib/main.dart
를 수정하여 간단한 Hello World UI를 구성했습니다.
자동 생성된 테스트는 아직 Counter 예제를 기준으로 하므로 현 상태에서는 실패합니다.
✅ 최종 점검 리스트
출처 : https://nomadcoders.co/flutter-for-beginners