0. Flutter TikTok Clone - 초기 프로젝트 세팅
Flutter 프로젝트 생성
📌 학습 목표
- Flutter 프로젝트의 기본 구조를 이해합니다
- MaterialApp의 기본 설정 방법을 배웁니다
- 프로젝트 초기 파일 구조를 파악합니다
- 테마 색상 설정 방법을 이해합니다
📂 파일 구조
1 | tiktok/ |
💻 초기 main.dart 코드
1 | import 'package:flutter/material.dart'; |
📖 코드 상세 설명
1. main() 함수
1 | void main() { |
- void main(): Dart 프로그램의 진입점(Entry Point)입니다
- runApp(): Flutter 앱을 시작하는 함수입니다
- const TikTokApp(): 앱의 최상위 위젯을 생성합니다
const
를 사용하여 컴파일 타임에 상수로 만들어 성능을 향상시킵니다
2. TikTokApp 클래스
1 | class TikTokApp extends StatelessWidget { |
- StatelessWidget: 상태가 변하지 않는 위젯입니다
- const 생성자: 불필요한 재빌드를 방지합니다
- super.key: 부모 클래스의 key 매개변수를 전달합니다
- key는 위젯을 고유하게 식별하는데 사용됩니다
3. MaterialApp 설정
1 | return MaterialApp( |
MaterialApp 속성 설명:
title: 앱의 제목
- 태스크 매니저에서 보이는 이름입니다
- iOS에서는 사용되지 않습니다
theme: 앱의 전체적인 테마 설정
ThemeData
: Material Design 테마를 정의합니다
colorScheme: 앱의 색상 체계
ColorScheme.fromSeed()
: 시드 컬러를 기반으로 전체 색상 팔레트를 자동 생성합니다seedColor: Color(0xFFE9435A)
: TikTok의 시그니처 핑크색0xFF
: 완전 불투명 (Alpha 255)E9435A
: RGB 값 (233, 67, 90)
useMaterial3: Material Design 3 사용 여부
false
: Material Design 2 사용 (기존 디자인 시스템)- Material 2는 더 안정적이고 검증된 디자인을 제공합니다
home: 앱의 기본 화면
- 현재는 빈
Container()
사용
- 현재는 빈
📦 pubspec.yaml 설정
1 | name: tiktok |
주요 설정 설명:
name: tiktok
- 프로젝트 이름 (패키지 이름으로 사용됩니다)
publish_to: ‘none’
- pub.dev에 실수로 배포되는 것을 방지합니다
- 개인 프로젝트에 권장됩니다
version: 1.0.0+1
- 앱 버전 번호
1.0.0
: 버전 이름 (사용자에게 보이는 버전)+1
: 빌드 번호 (내부적으로 사용하는 번호)
environment.sdk
- Dart SDK 버전 범위 지정
>=3.3.0 <4.0.0
: 3.3.0 이상, 4.0.0 미만
dependencies
- flutter: Flutter SDK
- cupertino_icons: iOS 스타일 아이콘 패키지
dev_dependencies
- flutter_test: 테스트 프레임워크
- flutter_lints: 코드 품질 검사 도구
uses-material-design: true
- Material Design 아이콘과 폰트를 사용 가능하게 합니다
🎨 시각적 다이어그램
프로젝트 구조
1 | ┌─────────────────────────────────────┐ |
앱 실행 흐름
1 | 1. main() 함수 실행 |
✅ 체크리스트
- Flutter 프로젝트가 정상적으로 생성되었는가?
- main.dart 파일이 lib/ 폴더에 있는가?
- MaterialApp의 테마 색상이 설정되었는가?
- useMaterial3가 false로 설정되었는가?
- constants 폴더가 생성되었는가?
- pubspec.yaml의 기본 설정이 완료되었는가?
🔑 핵심 개념 정리
개념 | 설명 | 왜 중요한가? |
---|---|---|
main() | 앱의 시작점 | 모든 Flutter 앱은 main()에서 시작합니다 |
runApp() | 위젯 트리를 화면에 렌더링 | Flutter 앱을 실행하는 필수 함수입니다 |
StatelessWidget | 불변하는 위젯 | 상태가 없어 더 효율적입니다 |
MaterialApp | Material Design 앱의 루트 | 네비게이션, 테마 등을 관리합니다 |
ColorScheme.fromSeed | 시드 컬러에서 팔레트 생성 | 일관된 색상 체계를 자동으로 만듭니다 |
const | 컴파일 타임 상수 | 불필요한 재빌드를 방지합니다 |
💡 실습 과제
색상 변경하기
1
2
3// 다른 색상으로 시도해보세요
seedColor: const Color(0xFF0000FF) // 파란색
seedColor: const Color(0xFF00FF00) // 초록색앱 제목 변경하기
1
title: 'My First App',
Material 3로 변경해보기
1
2useMaterial3: true,
// 차이점을 관찰해보세요
❓ 자주 묻는 질문
Q1: const를 왜 사용하나요?
A: const는 컴파일 타임에 상수로 만들어 불필요한 재빌드를 방지하고 메모리를 절약합니다. 변하지 않는 위젯은 항상 const로 만드는 것이 좋습니다.
Q2: StatelessWidget vs StatefulWidget 차이는?
A: StatelessWidget은 한 번 그려지면 변하지 않습니다. StatefulWidget은 setState()로 상태를 변경하고 다시 그릴 수 있습니다. 초기 설정에는 변할 일이 없으므로 StatelessWidget을 사용합니다.
Q3: ColorScheme.fromSeed의 장점은?
A: 하나의 시드 컬러에서 primary, secondary, background 등 전체 색상 팔레트를 자동으로 생성해 일관된 디자인을 유지할 수 있습니다.
Q4: 왜 home에 빈 Container()를 넣나요?
A: MaterialApp은 home이 필수이기 때문입니다. 나중에 실제 화면을 만들면 이 Container를 교체합니다.
Sizes 상수 시스템 구축
📌 학습 목표
- 크기 상수를 관리하는 시스템을 이해합니다
- 하드코딩을 피하는 방법을 배웁니다
- 일관된 디자인 시스템을 구축하는 방법을 학습합니다
- static const의 사용법을 익힙니다
📂 파일 위치
1 | lib/ |
💻 sizes.dart 전체 코드
1 | class Sizes { |
📖 코드 상세 설명
1. 클래스 구조
1 | class Sizes { |
- 왜 클래스를 사용하나요?
- 관련된 상수들을 하나로 묶어 관리합니다
- 네임스페이스 역할을 하여 다른 곳의 변수명과 충돌을 방지합니다
Sizes.size16
처럼 명확하게 사용할 수 있습니다
2. static const 키워드
1 | static const size16 = 16.0; |
static 키워드:
- 클래스 인스턴스를 생성하지 않고 사용할 수 있습니다
- 메모리에 한 번만 할당됩니다
Sizes.size16
처럼 클래스명으로 직접 접근합니다
const 키워드:
- 컴파일 타임에 값이 결정되는 상수입니다
- 런타임에 변경할 수 없습니다
- 메모리를 절약하고 성능을 향상시킵니다
왜 둘 다 사용하나요?
1 | // ❌ 나쁜 방법 |
3. 크기 값 체계
작은 크기 (1-12):
1 | static const size1 = 1.0; // 매우 작은 여백, 테두리 |
중간 크기 (14-32):
1 | static const size14 = 14.0; // 작은 패딩 |
큰 크기 (36-96):
1 | static const size36 = 36.0; // 아이콘 크기 |
🎯 사용 예시
Before (하드코딩 ❌)
1 | Container( |
After (상수 사용 ✅)
1 | Container( |
🎨 시각적 다이어그램
크기 체계 시각화
1 | 작은 크기 중간 크기 큰 크기 |
Sizes 클래스 사용 흐름
1 | ┌─────────────────────────────────────┐ |
💡 왜 이런 시스템이 필요한가?
1. 일관성 (Consistency)
1 | // ❌ 하드코딩: 비슷한 크기가 여러 곳에서 다르게 사용됨 |
2. 유지보수 (Maintainability)
1 | // ❌ 하드코딩: 모든 곳을 찾아서 수정해야 함 |
3. 가독성 (Readability)
1 | // ❌ 하드코딩: 의미를 알 수 없음 |
4. 디자인 시스템 (Design System)
1 | 모든 UI는 정해진 크기만 사용 |
✅ 체크리스트
- Sizes 클래스가 생성되었는가?
- static const로 모든 상수가 선언되었는가?
- 1부터 96까지 필요한 크기가 모두 포함되었는가?
- 타입이 double (1.0, 2.0…)로 되어 있는가?
🔑 핵심 개념 정리
개념 | 설명 | 예시 |
---|---|---|
static | 클래스 레벨 멤버 | Sizes.size16 인스턴스 없이 사용 |
const | 컴파일 타임 상수 | 변경 불가, 메모리 효율적 |
하드코딩 방지 | 숫자 직접 입력 금지 | 16.0 → Sizes.size16 |
디자인 시스템 | 일관된 크기 체계 | 모든 UI가 동일한 크기 사용 |
💡 실습 과제
Sizes 클래스를 사용하여 Container 만들기
1
2
3
4
5Container(
width: Sizes.size64,
height: Sizes.size64,
padding: EdgeInsets.all(Sizes.size16),
)자주 사용하는 크기 찾기
- 어떤 크기가 가장 많이 사용될 것 같나요?
- 패딩, 마진, 아이콘에 어떤 크기를 쓸까요?
없는 크기가 필요하다면?
1
2// 만약 size18이 필요하다면?
static const size18 = 18.0; // 추가!
❓ 자주 묻는 질문
Q1: 왜 size13, size15 같은 숫자는 없나요?
A: 디자인 시스템에서는 일관된 간격을 위해 특정 숫자만 사용합니다. 4의 배수나 자주 사용하는 숫자만 포함하여 선택의 폭을 줄이고 일관성을 높입니다.
Q2: double 타입 대신 int를 사용하면 안되나요?
A: Flutter에서 크기는 대부분 double을 사용합니다.
1
이 아닌1.0
을 사용하면 타입 변환 없이 바로 사용할 수 있어 편리합니다.
Q3: Sizes 클래스의 인스턴스를 만들어야 하나요?
A: 아니요! static이므로
Sizes.size16
처럼 클래스명으로 바로 접근합니다. 인스턴스를 만들 필요가 없습니다.
Q4: 다른 파일에서 어떻게 사용하나요?
A: 파일 상단에
import 'package:tiktok/constants/sizes.dart';
를 추가하면 됩니다.
Gaps 위젯 시스템 구축
📌 학습 목표
- 재사용 가능한 간격 위젯을 만드는 방법을 배웁니다
- Vertical과 Horizontal 간격의 차이를 이해합니다
- SizedBox 위젯의 활용법을 익힙니다
- const 위젯을 통한 성능 최적화를 학습합니다
📂 파일 위치
1 | lib/ |
💻 gaps.dart 전체 코드
1 | import 'package:flutter/material.dart'; |
📖 코드 상세 설명
1. import 문
1 | import 'package:flutter/material.dart'; |
package:flutter/material.dart:
- SizedBox 위젯을 사용하기 위해 필요합니다
- Flutter의 Material Design 위젯을 제공합니다
package:tiktok/constants/sizes.dart:
- 앞서 만든 Sizes 클래스를 사용하기 위해 import합니다
Sizes.size16
같은 상수를 사용할 수 있게 됩니다
2. Vertical Gaps (수직 간격)
1 | static const v16 = SizedBox(height: Sizes.size16); |
구성 요소:
- static const: Sizes와 동일하게 한 번만 생성되는 상수입니다
- v16: “vertical 16”의 약자입니다
- SizedBox: Flutter의 빈 공간을 만드는 위젯입니다
- height: 수직 방향의 크기를 지정합니다
- Sizes.size16: 앞서 만든 크기 상수를 재사용합니다
왜 SizedBox를 사용하나요?
1 | // SizedBox는 보이지 않는 빈 공간을 만듭니다 |
3. Horizontal Gaps (수평 간격)
1 | static const h16 = SizedBox(width: Sizes.size16); |
Vertical과의 차이:
- v16:
height
사용 → 위아래 간격 (↕) - h16:
width
사용 → 좌우 간격 (↔)
1 | Row( |
4. Sizes 클래스 재사용
1 | // Sizes의 값을 그대로 사용 |
장점:
- Sizes를 변경하면 Gaps도 자동으로 변경됩니다
- 중복된 숫자를 입력할 필요가 없습니다
- 일관성이 보장됩니다
🎯 사용 예시
Before (매번 SizedBox 작성 ❌)
1 | Column( |
After (Gaps 사용 ✅)
1 | Column( |
🎨 시각적 다이어그램
Vertical Gaps (수직 간격)
1 | ┌─────────────────┐ |
Horizontal Gaps (수평 간격)
1 | ┌──────┐ ┌──────┐ ┌──────┐ |
Gaps 클래스 구조
1 | ┌─────────────────────────────────────┐ |
💡 왜 Gaps 시스템이 필요한가?
1. 코드 간결성 (Simplicity)
1 | // ❌ 길고 복잡함 |
2. 타입 안정성 (Type Safety)
1 | // ❌ 실수 가능 |
3. 성능 최적화 (Performance)
1 | // const SizedBox는 한 번만 생성됨 |
4. 가독성 향상 (Readability)
1 | // ❌ 뭘 하는 건지 파악이 어려움 |
🔄 main.dart에서 Gaps 사용하기
1 | import 'package:flutter/material.dart'; |
변경 사항:
import 'package:tiktok/constants/sizes.dart';
추가EdgeInsets.all(Sizes.size14)
사용- 숫자
14.0
대신Sizes.size14
사용
✅ 체크리스트
- Gaps 클래스가 생성되었는가?
- Vertical Gaps (v1~v96)가 모두 정의되었는가?
- Horizontal Gaps (h1~h96)가 모두 정의되었는가?
- Sizes.dart를 import했는가?
- static const SizedBox로 정의되었는가?
- v는 height, h는 width를 사용하는가?
🔑 핵심 개념 정리
개념 | 설명 | 예시 |
---|---|---|
SizedBox | 빈 공간을 만드는 위젯 | SizedBox(height: 16) |
Vertical Gap | 위아래 간격 (Column) | Gaps.v16 |
Horizontal Gap | 좌우 간격 (Row) | Gaps.h16 |
const 위젯 | 한 번만 생성되는 위젯 | 메모리 절약, 성능 향상 |
재사용성 | Sizes 상수 재활용 | 일관성 유지 |
💡 실습 과제
Column에서 Gaps 사용하기
1
2
3
4
5
6
7
8
9Column(
children: [
Text('첫 줄'),
Gaps.v16,
Text('둘째 줄'),
Gaps.v24,
Text('셋째 줄'),
],
)Row에서 Gaps 사용하기
1
2
3
4
5
6
7
8
9Row(
children: [
Icon(Icons.star),
Gaps.h8,
Text('별점'),
Gaps.h16,
Text('5.0'),
],
)다양한 크기 실험하기
- Gaps.v8과 Gaps.v16의 차이를 확인해보세요
- Gaps.h24와 Gaps.h32를 비교해보세요
❓ 자주 묻는 질문
Q1: v와 h를 헷갈리면 어떻게 하나요?
A: v = vertical (수직, ↕), h = horizontal (수평, ↔)으로 기억하세요. Column은 세로 배치이므로 v를, Row는 가로 배치이므로 h를 사용합니다.
Q2: SizedBox 대신 Padding을 쓰면 안되나요?
A: Padding은 위젯을 감싸는 용도이고, SizedBox는 순수하게 빈 공간을 만듭니다. 간격을 만들 때는 SizedBox가 더 적합합니다.
Q3: 왜 모든 크기를 다 만드나요? 필요한 것만 만들면 안될까요?
A: 미리 다 만들어두면 나중에 일일이 추가할 필요가 없어 편리합니다. 사용하지 않는 것은 최적화 과정에서 제거됩니다.
Q4: const를 빼면 어떻게 되나요?
A: 작동은 하지만 매번 새로운 SizedBox가 생성되어 메모리를 낭비하고 성능이 떨어집니다.
FVM 버전 관리 설정
📌 학습 목표
- FVM(Flutter Version Management)의 개념을 이해합니다
- 프로젝트별 Flutter 버전 관리 방법을 배웁니다
- .fvmrc 설정 파일의 역할을 이해합니다
- Flutter 버전 업데이트 과정을 학습합니다
📂 관련 파일
1 | 프로젝트 루트/ |
💻 설정 파일 내용
1. .fvmrc
1 | { |
역할:
- 프로젝트에서 사용할 Flutter 버전을 지정합니다
- FVM이 이 파일을 읽고 해당 버전을 활성화합니다
- 팀원 모두가 같은 Flutter 버전을 사용하게 합니다
2. .fvm/fvm_config.json
1 | { |
역할:
- FVM 내부 설정 파일입니다
- 실제 사용 중인 Flutter SDK 버전 정보를 저장합니다
- .fvmrc와 동기화됩니다
3. .gitignore 추가
1 | # FVM Version Cache |
왜 flutter_sdk를 ignore하나요?
flutter_sdk
는 실제 Flutter SDK로의 심볼릭 링크입니다- 각 개발자의 컴퓨터마다 경로가 다릅니다
- Git에 포함하지 않고 FVM이 자동으로 생성하게 합니다
4. .vscode/settings.json 추가
1 | { |
각 설정의 의미:
- dart.flutterSdkPath: VSCode가 FVM의 Flutter SDK를 사용하도록 지정
- search.exclude: .fvm 폴더를 검색에서 제외
- files.watcherExclude: .fvm 폴더 변경 감지 제외 (성능 향상)
📖 FVM 상세 설명
1. FVM이란?
1 | FVM (Flutter Version Management) |
왜 필요한가?
1 | 프로젝트 A → Flutter 3.32.8 필요 |
2. FVM 작동 원리
1 | 1. FVM이 여러 Flutter 버전을 저장 |
3. 커밋 변경 사항 분석
변경된 파일 7개:
- .fvmrc: Flutter 버전을 3.32.8로 지정
- .gitignore: FVM 캐시 ignore 추가
- .vscode/settings.json: VSCode FVM 설정
- ios/…/Runner.xcscheme: iOS 빌드 설정 업데이트
- ios/Runner/AppDelegate.swift: iOS 앱 델리게이트 업데이트
- pubspec.lock: 종속성 버전 업데이트
- pubspec.yaml: SDK 버전 범위 업데이트
pubspec.yaml 변경:
1 | environment: |
🎨 시각적 다이어그램
FVM 버전 관리 흐름
1 | ┌────────────────────────────────────────┐ |
버전 전환 과정
1 | Step 1: 프로젝트 폴더 진입 |
💡 FVM 사용법
1. FVM 설치 (최초 1회)
1 | # macOS/Linux |
2. Flutter 버전 설치
1 | # 특정 버전 설치 |
3. 프로젝트에 버전 설정
1 | # 프로젝트 폴더에서 |
4. FVM Flutter 명령어 실행
1 | # FVM을 통해 Flutter 명령어 실행 |
🔧 팀 협업 시나리오
상황: 새 팀원이 프로젝트 clone
1 | # 1. 프로젝트 clone |
팀원 모두 같은 Flutter 버전 사용! ✅
✅ 체크리스트
- FVM이 설치되어 있는가?
- .fvmrc 파일이 생성되었는가?
- Flutter 버전이 3.32.8로 설정되었는가?
- .gitignore에 .fvm/flutter_sdk가 추가되었는가?
- VSCode settings.json이 설정되었는가?
-
fvm flutter --version
으로 버전 확인이 되는가?
🔑 핵심 개념 정리
개념 | 설명 | 예시 |
---|---|---|
FVM | Flutter 버전 관리 도구 | 프로젝트별 다른 Flutter 버전 |
.fvmrc | 프로젝트 Flutter 버전 지정 | {"flutter": "3.32.8"} |
심볼릭 링크 | 다른 위치를 가리키는 링크 | .fvm/flutter_sdk → ~/fvm/versions/3.32.8 |
버전 일관성 | 팀원 모두 같은 버전 사용 | 환경 차이로 인한 버그 방지 |
💡 실습 과제
현재 Flutter 버전 확인
1
fvm flutter --version
설치된 FVM 버전 목록 보기
1
fvm list
프로젝트 Flutter 버전 확인
1
cat .fvmrc
다른 버전 설치해보기
1
2fvm install 3.10.0
# 여러 버전 관리 가능!
❓ 자주 묻는 질문
Q1: FVM 없이 개발하면 안되나요?
A: 가능하지만, 팀원마다 다른 Flutter 버전을 사용하면 “내 컴퓨터에서는 되는데?” 같은 문제가 발생합니다. FVM으로 버전을 통일하는 것이 좋습니다.
Q2: .fvm 폴더를 Git에 포함해야 하나요?
A: .fvmrc와 fvm_config.json만 포함하고, flutter_sdk는 제외합니다. 각 개발자가 FVM으로 자동 생성하게 합니다.
Q3: VSCode가 올바른 Flutter SDK를 못 찾으면?
A: VSCode를 재시작하거나 Command Palette(Cmd+Shift+P)에서 “Reload Window”를 실행하세요.
Q4: Flutter 버전을 업데이트하려면?
A:
1
2 fvm install 3.33.0 # 새 버전 설치
fvm use 3.33.0 # 프로젝트에 적용
Q5: fvm flutter와 flutter 명령어 차이는?
A:
fvm flutter
는 프로젝트에 설정된 버전을 사용하고,flutter
는 시스템 전역 버전을 사용합니다. FVM 프로젝트에서는 항상fvm flutter
를 사용하세요.
🎓 전체 복습 및 요약
📚 배운 내용 정리
이번 강의에서 배운 4가지 핵심 주제:
Flutter 프로젝트 생성
- MaterialApp 기본 구조
- 테마와 색상 설정
- 프로젝트 파일 구조
Sizes 상수 시스템
- static const를 사용한 크기 관리
- 하드코딩 방지
- 일관된 디자인 시스템
Gaps 위젯 시스템
- SizedBox를 활용한 간격 관리
- Vertical/Horizontal 구분
- 재사용 가능한 위젯
FVM 버전 관리
- 프로젝트별 Flutter 버전 관리
- 팀 협업 환경 구축
- 버전 일관성 유지
🔗 개념 연결 맵
1 | ┌───────────────────────────────────┐ |
💪 실전 프로젝트 시작하기
이제 배운 내용을 바탕으로 실전 코드를 작성할 준비가 되었습니다!
다음 단계:
- Sizes와 Gaps를 활용한 UI 구성
- 실제 화면 만들기 (SignUpScreen, LoginScreen 등)
- 네비게이션과 라우팅
- 상태 관리
🎯 최종 체크리스트
프로젝트 기본 설정:
- Flutter 프로젝트가 생성되었다
- MaterialApp이 설정되었다
- 테마 색상이 적용되었다
디자인 시스템:
- Sizes 클래스가 완성되었다
- Gaps 클래스가 완성되었다
- main.dart에서 Sizes를 사용하고 있다
개발 환경:
- FVM이 설치되었다
- Flutter 3.32.8이 설정되었다
- VSCode가 FVM을 인식한다
- 팀원도 같은 환경을 구축할 수 있다
📝 핵심 코드 패턴 정리
1 | // 1. 크기 사용 |
📚 부록
A. 명령어 정리
Flutter 명령어:
1 | flutter create tiktok # 프로젝트 생성 |
FVM 명령어:
1 | fvm install 3.32.8 # Flutter 버전 설치 |
Git 명령어:
1 | git log --oneline # 커밋 히스토리 확인 |
B. 트러블슈팅
문제 1: FVM 명령어를 찾을 수 없음
1 | # PATH에 dart pub global 경로 추가 |
문제 2: VSCode가 Flutter SDK를 찾지 못함
1 | // .vscode/settings.json 확인 |
문제 3: Sizes/Gaps를 찾을 수 없음
1 | // import 확인 |
C. 유용한 VSCode 확장
- Flutter - Flutter 개발 필수
- Dart - Dart 언어 지원
- Pubspec Assist - 패키지 추가 도우미
- Error Lens - 에러 인라인 표시
- GitLens - Git 기능 강화