프로젝트에서 보기 →

Flutter 입문 2시간 무료강의 - 모바일 앱 개발 실습 포함 | (주)올리고컴퍼니 기술이사 홍정민

태그
기타 플러터 flutter 앱개발
시작일
종료일
수정일

https://www.youtube.com/watch?v=mOtWvKkvC7A

description: |-

1. 이건 꼭 알아야 한다[^1]

[? 질문] 모바일 앱(안드로이드/iOS)을 만드는 대표적인 방식들은 무엇이며, 각 방식의 장단점은 무엇인가[^12]
[= 답] 네이티브/웹뷰 기반 웹/하이브리드/크로스플랫폼으로 나뉘며, 성능·사용자경험·개발비용·플랫폼 호환성 관점에서 트레이드오프가 존재한다(네이티브는 최고 성능이지만 코드베이스 2개, 웹은 배포가 빠르지만 “웹같이” 보임, 하이브리드는 깜빡임은 줄지만 웹뷰 한계, 크로스플랫폼은 코드 1개로 양 플랫폼 대응).[^13][^18][^24]

[? 질문] Flutter로 앱을 개발하려면 무엇을 설치·설정해야 하고, “프로젝트 생성→실행”까지 최소 흐름은 어떻게 되는가[^26]
[= 답] Android Studio 설치 → Flutter SDK 설치(Windows는 환경변수 PATH에 flutter/bin 추가) → Android Studio에 Flutter 플러그인 설치 → Flutter 프로젝트 생성(패키지명/조직명 포함) → 에뮬레이터(AVD) 또는 실기기 연결 후 Run으로 실행, Hot Reload로 UI 변경을 즉시 확인한다.[^35][^54][^86]

[? 질문] Flutter/다트(Dart) 초심자가 반드시 익혀야 하는 언어 핵심 5요소는 무엇이고, 왜 중요한가[^93]
[= 답] 데이터(단일/복수), 함수(재사용·매개변수·리턴), 조건문, 반복문, 클래스(규격화된 복합 데이터 타입/객체 지향의 기반)이며, 이 5가지로 프론트·백엔드·앱 개발 전반의 로직을 대부분 구성할 수 있다.[^95][^125]

[? 질문] Flutter에서 “데이터가 바뀌면 화면(UI)이 자동으로 바뀌지 않는 이유”와, UI를 갱신하는 방법은 무엇인가[^220]
[= 답] 단순히 변수 값만 변경해도 UI가 다시 그려지지 않기 때문에, 상태(State)가 바뀌었음을 프레임워크에 알리고 “다시 빌드(리빌드)”하도록 해야 한다. StatefulWidget에서는 setState()로 상태 변경+리빌드를 트리거한다.[^221][^228]

[? 질문] 앱이 서버(REST API)에 요청해 JSON을 받아 화면에 보여주려면, 어떤 개념·도구·코드 구조가 필요한가[^248]
[= 답] REST API(URL로 데이터 송수신) 이해 → http 패키지 추가(pub.dev) → 비동기(Future/async/await)로 GET 요청 → 응답 body(JSON 문자열)를 jsonDecode로 Map/List로 변환 → setState로 UI에 반영 → 필드가 많아지면 모델(VO) 클래스로 매핑(fromJson)해 UI코드와 데이터 로직을 정리한다.[^253][^285][^312]

2. 큰 그림[^6]

이 강의는 Flutter를 처음 접하는 학습자를 대상으로, 앱 개발 방식의 전체 지형을 정리한 뒤 Flutter 개발환경을 설치·실행하고, Dart 언어 핵심 문법을 실습으로 익힌 다음, 위젯(UI) 구성과 상태 변경(setState), REST API 통신 및 JSON→모델 변환까지 “앱이 동작하는 최소 단위”를 직접 구현하는 흐름으로 구성된다.[^12][^86][^228]

  • Flutter는 크로스플랫폼으로, 하나의 코드베이스로 안드로이드/iOS를 동시에 개발·배포하는 것을 목표로 하며, 플랫폼 위에 “새로 그려나가는 방식” 비유로 호환성/일관된 UI를 설명한다.[^24][^26]
  • Flutter의 UI는 전부 위젯(Widget) 이며, 위젯 트리/속성(key-value) 조합으로 화면을 구성한다(Scaffold, Container, Column/Row, Text, Image, Button 등).[^7][^185]
  • 앱은 결국 서버·DB와 연결되어야 하므로 REST API + HTTP 요청 + JSON 파싱 + 상태 반영이 중요하고, 규모가 커지면 모델(VO) 클래스로 데이터 구조를 규격화해 유지보수성을 높인다.[^248][^302]

3. 하나씩 살펴보기[^1]

3.1 강사 소개, 수업 자료/진행 방식[^2]

📸 0:04

강사는 KISA(키사)에서 진행하는 웹테크 밋업에서 Flutter 강의를 맡은 홍정민이며, (주)올리고컴퍼니 기술이사로 개발 총괄을 맡고 있다고 소개한다.[^2][^3] 또한 한국 기술사업화 진흥협회 대구지사에서 K-디지털 강의들을 진행해왔고, 현업에서 쓰는 실무 기술을 수업에서 최대한 전달하겠다고 강조한다.[^3][^4]

수업 자료는 제공되는 PDF와 별도의 노션(Notion) 자료를 병행하고, 진행 방식은 “코드 중심”으로 하되 개념 설명은 PDF/노션으로 보완하겠다고 안내한다.[^5][^6] 강의 목차는 모바일 앱 개발 방식 소개 → Dart 언어 기초 → 위젯 → 상태관리 → REST API(HTTP)로 데이터 요청 → Provider와 HTTP 데이터 결합 등으로 잡았지만, 이해를 위해 유동적으로 진행한다고 말한다.[^7][^8]

3.2 모바일 앱 개발 방식 4가지: 네이티브/웹/하이브리드/크로스플랫폼[^12]

📸 2:35

강의는 먼저 모바일 OS가 안드로이드(구글)와 iOS(애플) 두 가지이며, 이 플랫폼에서 서비스가 동작하도록 만드는 프로그램이 앱(어플리케이션)이라는 점을 상기시킨다.[^12][^13] 문제는 안드로이드와 iOS는 개발 언어·패턴이 달라 “둘 다 만들려면” 개발 방식 선택이 중요해진다는 맥락을 제시한다.[^14]

3.2.1 네이티브 앱(Native App)[^15]

네이티브 앱은 각 플랫폼의 고유 언어/기술로 개발하는 방식이다.[^15] 예로 안드로이드는 Java/Kotlin, iOS는 Objective-C/Swift 등을 든다.[^15]

  • 장점: 최고의 성능, 반응성.[^16]
  • 단점: 코드베이스가 2개(플랫폼별 별도 개발)라서 개발 인력/비용이 2배에 가까워질 수 있다.[^16][^17]
  • 적합한 경우: 고성능/빠른 수행이 필수인 앱에서 전통적으로 사용해왔으나, 최근 스마트폰 성능이 좋아져 타 방식도 대체로 잘 돌아간다는 뉘앙스를 덧붙인다.[^18]

3.2.2 웹(Web) + 웹뷰(WebView)[^19]

웹은 “모바일 화면에 맞춘 웹사이트”를 만들고, 네이티브 앱의 웹뷰 기능으로 전체 화면에 사이트를 띄우는 방식으로 설명한다.[^19] 즉 URL을 웹뷰에 넣으면 앱처럼 보이지만 본질은 웹사이트라는 것이다.[^19]

  • 장점: 배포가 빠르고, 앱을 “딥하게” 공부하지 않아도 웹 개발자도 쉽게 개발 가능.[^20]
  • 단점: 사용자도 웹사이트처럼 보인다고 느낄 정도로 UX 차이가 드러날 수 있음(화면 전환 깜빡임, 애니메이션/전환 가속도 등의 차이).[^21]
  • 적합한 경우: 빠른 배포, 컨텐츠 중심(뉴스/커머스/포털 등)처럼 내용이 많은 기존 웹서비스를 앱화할 때. 웹을 네이티브로 옮기려면 앱 코드 작업량이 커지기 때문에 웹이 유리하다고 설명한다.[^22]

3.2.3 하이브리드 앱(Hybrid App)[^23]

강사는 “리액트 네이티브나 플러터”를 하이브리드로 오해하는 경우가 있다고 말하면서, 여기서 말하는 하이브리드는 “웹앱의 프런트 코드를 앱 내부에 포함”해 웹뷰에서 실행하는 방식이라고 정의한다.[^23] 브라우저가 서버에서 프런트를 내려받는 웹과 달리, 하이브리드는 프런트 코드가 앱 안에 있어 깜빡임이 줄어든다고 설명한다.[^23]

  • 장점: 웹처럼 내려받는 과정이 아니라서 화면 깜빡임이 없음.[^23]
  • 단점: 웹뷰 성능의 한계, 복잡한 애니메이션 처리 한계, HTML 기반 UI 구성의 제약 등.[^23]

3.2.4 크로스 플랫폼(Cross Platform): React Native vs Flutter[^24]

2014년 페이스북(현재 메타)이 React/React Native를 발표했고, React Native가 크로스플랫폼의 대표 사례가 되었다고 소개한다.[^24] 크로스플랫폼의 핵심은 “하나의 코드베이스로 iOS/안드로이드 모두 배포”하는 것이다.[^24]

  • React Native: 자바스크립트 기반이며, 필요한 네이티브 코드를 꺼내 쓰는 구조로 설명한다.[^24]
  • 장점: 코드 1개로 두 OS 대응.[^24]
  • 단점(Flutter와 비교 관점): 네이티브 코드를 호출하기 때문에 OS/버전별 분기 처리가 많아질 수 있고, 블루투스/NFC 같은 복잡 기능에서 오픈소스/플러그인 상황에 따라 어려움이 있을 수 있다고 말한다.[^24]

2019년 구글이 Flutter를 발표했고, Flutter도 동일하게 크로스플랫폼이지만 언어는 Dart를 사용한다고 설명한다.[^25] Flutter의 방식 차이는 “운영체제 위에 흰 도화지를 얹어 새로 그려나간다”는 비유로 설명하며, OS와 상관없이 UI를 렌더링하는 방식이라 호환성이 우수하다고 주장한다.[^25] 또한 Flutter가 안드로이드/iOS뿐 아니라 맥OS, 윈도우, 웹 등 모든 플랫폼을 목표로 계속 확장 중이라고 언급한다.[^25]

강사 개인 경험으로는 React Native와 Flutter를 모두 공부해봤고, Flutter가 더 배우기 쉽고 커뮤니티도 더 잘 되어 있어 앱개발 주력으로 Flutter를 사용하고 있다고 말한다.[^26]

3.3 개발 환경 구축: Android Studio, Flutter 설치, 환경 변수, 플러그인, 프로젝트 생성[^27]

📸 10:13

강사는 수업 도구로 Android Studio를 사용해 Flutter 개발을 진행한다고 밝힌다.[^27] 최근 Cursor AI 등 다양한 AI 도구가 있지만 비용 문제가 있고, 무엇보다 AI를 활용하려면 “Flutter 코드 원리”를 알아야 하므로 기본기를 먼저 잡자는 취지라고 설명한다.[^27]

3.3.1 설치해야 할 것들(Windows 기준)과 이유[^28]

  • Android Studio 설치: 메모장으로도 개발은 가능하지만 현실적으로 어렵고, IDE의 문법 하이라이트/개발 편의가 필요하다고 말한다.[^28]
  • Flutter SDK 별도 설치: flutter 명령어 사용을 위해 환경 변수 설정이 필요하다.[^29]
  • Android Studio에 Flutter 플러그인 설치: IDE가 Flutter 문법/기능을 이해하도록 하는 단계.[^29]
  • Flutter 동작 확인: flutter doctor로 개발 가능 여부를 진단한다고 설명한다.[^30]

강사는 공식 문서를 보고 설치하는 것을 권장하며, GPT가 답을 주더라도 결국 공식 문서 기반이므로 문서 기반으로 원리를 이해하는 게 중요하다고 말한다.[^31]

3.3.2 Windows 환경 변수(PATH)에 flutter/bin 등록[^33]

Flutter 설치 후 flutter/bin 경로를 시스템 PATH에 추가해야 CMD에서 flutter 명령이 동작한다고 설명한다.[^33]

  • 내 PC → 속성 → 고급 시스템 설정 → 환경 변수에서 “시스템 변수의 Path”를 편집해 Flutter bin 경로를 추가하는 과정을 보여준다.[^34]
  • 이후 CMD에서 flutter를 입력하면 명령 목록이 나오며, flutter doctor는 “의사처럼 진단”해 개발환경을 점검한다고 비유한다.[^30][^35]
  • 안드로이드 개발을 위해 라이선스 동의가 필요하며, flutter doctor --android-licenses를 실행하고 질문에 y 입력/엔터로 진행한다고 안내한다.[^35]

3.3.3 Android Studio 플러그인 설치와 Flutter 프로젝트 생성[^36]

Android Studio에서 Plugins(마켓플레이스)에서 Flutter를 설치하고 IDE를 재시작하면 “New Flutter Project” 메뉴가 생긴다고 설명한다.[^36] “New Project”는 네이티브, “New Flutter Project”가 Flutter 프로젝트라고 구분해준다.[^37]

프로젝트 생성 단계에서:

  • Flutter SDK 경로 설정: Flutter 폴더(상위)까지 지정하고 bin은 제외하라고 안내한다.[^38]
  • 프로젝트 이름 규칙: 소문자 + 언더스코어 권장, 대문자 사용 시 에러가 날 수 있다고 설명한다.[^39]
  • 조직명/패키지명(organization): com.company.app 형태로 고유해야 하고, 스토어 배포 시 중복되면 업로드가 안 되므로 신중해야 한다고 강조한다.[^40]
  • Android/iOS만 체크: 나머지 플랫폼은 아직 지원이 상대적으로 미흡할 수 있어, 앱개발 중심이면 Android/iOS만 선택하라고 말한다.[^41]

3.3.4 실행: 에뮬레이터(AVD) 또는 실기기[^42]

실행 방법은 2가지:

  1. 에뮬레이터(AVD) 실행
  2. USB로 스마트폰 연결 후 빌드/설치[^42]

강의에서는 시연을 위해 에뮬레이터를 사용하며, Device Manager에서 디바이스를 선택/생성할 수 있음을 보여준다.[^43] 에뮬레이터가 IDE 내부에 뜨는 경우/외부 창으로 뜨는 경우 설정을 설명하며, Settings에서 emulator 관련 옵션 체크 해제로 외부 창 실행도 가능하다고 말한다.[^44] 에뮬레이터 크기는 단축키(컨트롤+휠/방향키 조합) 등으로 조절 가능하다고 안내한다.[^45]

3.3.5 첫 실행과 Flutter 프로젝트 구조, Hot Reload[^46]

Run을 눌러 기본 카운터 예제가 실행되며, 첫 빌드는 3~5분 정도 걸릴 수 있다고 말한다.[^46] 빌드 중에 프로젝트 구조를 훑는데, Android/iOS 폴더가 있고 실제 Flutter 코드는 lib/main.dart에 있다고 설명한다.[^47]

  • 앱 실행의 시작점: 앱 클릭 → main() 함수 실행.[^48]
  • 위젯 구조: MyApp 같은 위젯 클래스가 실행되고, StatefulWidget/State 구조가 있음을 “일단 구조를 보자”는 수준으로 훑는다.[^49]
  • Hot Reload: 코드에서 색상을 바꾸면 거의 즉시 UI가 바뀌는 것을 보여주며, 이것이 Flutter의 Hot Reload 기능이라고 설명한다.[^50]
  • Scaffold 구성요소: AppBar(상단 바), FloatingActionButton(우하단 + 버튼) 등을 지우면 즉시 사라지는 것을 시연하며 개발 속도가 빠르다고 강조한다.[^51]

이 시점에서 “다음은 Dart 언어를 공부해야 한다”고 연결한다.[^52]

3.4 Dart 언어 핵심 5요소(데이터/함수/조건/반복/클래스)와 DartPad 실습[^93]

📸 30:53

강사는 언어 학습을 “공부 그 자체”라기보다 “서비스를 만들기 위한 수단”으로 보라고 말한다.[^93] 먼저 생산적인 개발을 하고 필요할 때 공부로 업그레이드하라는 접근을 강조한다.[^93]

언어를 배울 때 공통으로 중요한 5가지로 데이터, 함수, 조건문, 반복문, 클래스를 제시하며, 이것만으로도 백엔드/프런트/앱 개발 대부분을 할 수 있다고 말한다.[^95]

3.4.1 데이터: 단일 값 vs 여러 값(List/Map)[^96]

데이터는 로직 수행에 필수이며 “데이터가 변환되는 것 자체가 로직”이라고 정의한다.[^96] 타입에는 숫자, 문자, bool 등이 있고, 여러 개는 리스트/맵이 있다고 소개한다.[^97]

  • 단일 값: int/string/bool/double 등[^97]
  • 여러 값:
    • List: 순서가 있고 인덱스로 접근[^98]
    • Map: key-value로 저장하고 key로 접근[^98]

DartPad(웹에서 다트 실행)로 void main(){ print('hello'); }를 실행해 출력 확인을 하며 실습 중심으로 진행한다.[^99]

(1) 단일 타입 실습: int/string/bool/double[^100]

  • int a = 10;처럼 숫자를 저장하며, 타입과 맞지 않는 값을 넣으면 안 된다고 설명한다.[^100]
  • String a1 = '안녕';처럼 따옴표로 문자열을 저장하고 print(a1)로 출력 확인을 반복해보라고 한다.[^101]
  • bool a2 = true/false만 가능하며, “맞다/아니다” 이지선다 상황이 개발에서 매우 자주 등장하므로 최적화된 타입이라고 설명한다.[^102]
  • double은 소수점 숫자(예: 3.14)이며, 숫자형은 int로도 충분히 커버된다고 언급한다.[^103]

(2) List 실습: 타입 지정, 인덱스(0부터), 범위 오류[^104]

리스트는 “트럭에 짐을 싣고 온다” 비유로, 꺾쇠 <String>은 트럭에 실리는 짐(요소)의 타입을 정하는 것이라고 설명한다.[^104]

  • List<String> users = ['철수','민지','지원'];처럼 선언하고, 문자열 리스트에 숫자를 넣으면 타입 오류가 난다고 보여준다.[^105]
  • 인덱스 접근은 users[0]이며, 언어는 0부터 시작한다고 강조한다.[^106]
  • 존재하지 않는 인덱스(예: users[3])는 에러가 나며, 자바스크립트는 undefined처럼 언어 차이가 있다고 덧붙인다.[^107]

(3) Map 실습: Map<String, dynamic> 패턴, 중첩(List inside Map) 접근[^108]

맵은 Map<키타입, 값타입>이며, 키는 사람이 읽기 쉬운 문자열이 보통이라 String을 많이 쓴다고 설명한다.[^108] 값은 실무에서 문자/숫자/리스트 등 섞이므로 dynamic을 많이 써서 Map<String, dynamic> 패턴이 흔하다고 말한다.[^109]

예시로 {'name':'홍길동','age':20,'items':['노트북','볼펜']} 같은 구조를 만들고:

  • map['age']처럼 키로 접근[^110]
  • 중첩 리스트는 map['items'][1]로 볼펜을 꺼내는 시연을 한다.[^110]

(4) var vs dynamic: 동적 타입의 차이[^111]

Dart는 자바스크립트와 자바 성격이 섞여 있으며 vardynamic 차이를 강조한다.[^111]

  • var: 최초 할당 시 타입이 결정되고 이후 바뀌지 않는다.[^112]
  • dynamic: 타입을 자유롭게 바꿀 수 있다.[^113]
  • 실무에서는 값의 타입이 계속 바뀌는 경우가 드물어서 dynamic은 잘 안 쓰고 var를 주로 쓴다고 조언한다.[^114]

3.4.2 널 세이프티(Null Safety): ?, 초기값, late 3가지 방식[^115]

Flutter 최신 버전은 null safety를 적용하며, 값이 없을 수 있는 상황(null)을 컴파일 단계에서 최대한 방지하려는 목적이라고 설명한다.[^115] “박스에서 값을 꺼냈는데 있는 줄 알았더니 없는 것”이 null 에러라는 비유를 든다.[^116]

널 세이프티 처리 방법 3가지:

  1. 타입 뒤에 ?를 붙여 nullable임을 명시 (String? c;)[^117]
  2. 초기값을 지정 (String c = '';) — 공백과 null은 다르다고 설명[^118]
  3. late를 붙여 “나중에 반드시 세팅할 테니 믿어달라”(지연 초기화) — 하지만 세팅 없이 사용하면 런타임 에러 가능[^119]

3.4.3 함수: 재사용, 매개변수(위치/명명), 리턴(return) 개념[^120]

함수는 “여러 로직에 이름(별칭)을 주는 것”이며, 중요한/반복 로직을 호출로 재사용하는 도구라고 정의한다.[^120]

(1) 함수 선언 vs 호출[^121]

  • void addSixToTwenty(){ ... }처럼 선언하고
  • addSixToTwenty();로 호출한다고 설명한다.[^121]

(2) 매개변수(파라미터): 위치 매개변수 예시[^122]

10+20처럼 고정된 값만 더하면 활용성이 떨어지므로, 함수가 데이터를 받도록 매개변수를 사용해야 한다고 설명한다.[^122]

  • 예: void addTwoNumbers(int number1, int number2){ ... }
  • 호출 시 addTwoNumbers(10, 50)처럼 매개변수 개수/순서에 맞게 인자를 넣어야 하며, 그렇지 않으면 에러가 난다고 시연한다.[^123]

(3) 리턴(return): 호출한 쪽에서 결과를 “받아야” 다음 로직/UI로 활용 가능[^124]

함수는 로직 수행 후 값을 반환할 수 있으며, 반환 타입은 함수 선언부 타입과 맞아야 한다고 설명한다.[^124]

  • bool을 리턴하면 true/false 반환 가능[^124]
  • “60이 뭔지 아는 것과, 그 값을 받아서 UI로 바꾸는 것은 다르다”는 표현으로, 리턴을 받아 변수에 담아야 실제 활용이 가능하다고 강조한다.[^124]

(4) 명명된 매개변수(named parameter) + required/기본값/nullable 처리[^126]

다트는 중괄호 {}로 감싼 명명된 매개변수를 지원하며, 매개변수가 많아질수록 위치 매개변수는 읽기 어렵고 명명된 방식이 유리하다고 말한다.[^126][^127]

  • 명명된 매개변수에서 null safety로 인해:
    • ?로 nullable
    • 기본값 지정
    • required로 필수 입력을 강제할 수 있다고 설명한다.[^128]
  • 호출 시 func(number1: 10, number2: 20)처럼 키:값 형태로 전달하므로 가독성이 좋다고 한다.[^129]

3.4.4 조건문(if/else if/else): 조건식은 bool을 반환해야 함[^130]

조건문에서 if( ? ) 괄호 안에는 “조건식”이 들어가며, 정확히는 bool(true/false)만 들어갈 수 있다고 강조한다.[^130]
점수 예시로 score == 100 같은 비교 연산을 넣으면 그 비교 결과가 true/false를 리턴하므로 if가 동작한다고 설명한다.[^131]

  • if가 true면 해당 블록 실행, false면 넘어감[^132]
  • else는 if가 false일 때 실행되는 분기[^132]
  • else if는 추가 조건을 연쇄로 검사하는 구조[^133]

특히 if 체인의 핵심 규칙 2가지를 정리한다:

  1. 위에서부터 내려오며 “처음 true가 나오면 그 뒤는 보지 않고 전체 탈출”[^134]
  2. 조건식은 꼭 같은 변수(score)만 검사할 필요 없이 서로 다른 조건식들도 가능하지만, 실무에선 한 데이터에 대해 여러 조건을 묻는 경우가 많으니 깔끔하게 정리하라고 조언한다.[^135]

3.4.5 반복문(for): 0~99 출력, length 기반 순회, for-in 문법[^136]

for(int i=0; i<100; i++) print(i);를 통해 0부터 99까지 출력되는 것을 보여주며, 반복문의 프로세스(초기값→조건식 검사→실행→증가→재검사→탈출)를 단계별로 설명한다.[^136][^137]

백엔드에서 회원 리스트를 받았을 때 UI로 보여주려면 “한 번에 변경되지 않으므로” 반복으로 하나씩 꺼내 UI로 변환해야 한다는 맥락을 다시 연결한다.[^98][^138]

  • members.length를 사용해 데이터 개수가 달라져도 안전하게 순회하도록 설명한다.[^138]
  • for (var m in members) 형태의 for-in 문법도 가능하며, 원리는 결국 인덱스를 증가시키며 꺼내는 것이라고 정리한다.[^139]

3.4.6 클래스(Class): 규격화된 복합 타입, 생성자, this, 메서드, 네임드 생성자 패턴[^140]

강사는 클래스가 객체지향 등으로 어렵게 느껴질 수 있으나, 본인 관점에서는 “여러 값을 받는 데이터 타입”이라고 정의한다.[^140] 리스트/맵도 여러 값을 담지만, 클래스는 “정해진 항목(필드)만 들어가는 규격”이 있다는 점이 다르다고 말한다.[^141]

(1) 클래스가 필요한 이유: 같은 패턴 데이터 관리[^142]

강아지/고양이 나이 같은 유사한 데이터 패턴이 많고, 이를 변수로 흩뿌리면 관리가 힘들다.[^142]
맵을 쓰면 기준이 없어 아무 키나 들어갈 수 있으니(규격 없음) 애매하고, 이럴 때 클래스로 규격화하면 좋다고 설명한다.[^142][^143]

(2) Animal 클래스 예시: 필드 + 생성자 + this[^144]

class Animal { String type; int age; ... }처럼 필드를 만들고, 생성자(클래스명과 동일)를 함수처럼 정의해 값을 세팅한다고 설명한다.[^144]
생성자에서 파라미터와 필드 이름이 겹칠 수 있으므로 this.type = type;처럼 this로 “현재 클래스의 필드”임을 명확히 하라고 말한다.[^145]

null safety 에러는 초기값 제공 또는 nullable/late 등으로 해결할 수 있음을 언급한다.[^146]

이후 Animal dog = Animal('강아지', 2);처럼 인스턴스를 만들고, 점(.)으로 필드 접근(dog.type)이 가능함을 보여준다.[^147]

(3) 객체 지향의 직관: “속성 추가는 클래스에 한다”[^148]

“이름(name) 필드를 추가하려면 어디에 작업하냐? 클래스에 한다”는 예로, 우리가 자연스럽게 객체를 중심으로 기능/데이터를 확장하는 것이 객체지향이라고 설명한다.[^148]

(4) 클래스 안에 함수(메서드) 추가 + 문자열 보간(interpolation)[^149]

클래스에는 필드뿐 아니라 함수도 넣을 수 있으며, 예로 sayHello() 메서드를 만들고 print('... ${this.type} ...') 형태의 문자열 보간을 설명한다.[^149]
인스턴스에서 dog.sayHello()처럼 호출할 수 있고, 수정이 필요하면 클래스 내부만 바꾸면 되어 분화/유지보수에 유리하다고 정리한다.[^150]

(5) 네임드 파라미터 스타일의 생성자(가독성) 소개[^151]

Flutter 위젯들이 키:값 형태를 많이 쓰는 이유를 “명명된 생성자/파라미터가 가독성이 좋기 때문”이라고 연결한다.[^151]
생성자에서 { this.type, this.age } 형태로 받고 기본값을 둘 수 있으며, 호출 시 Animal(type: '강아지', age: 2)처럼 작성해 필드가 많아져도 읽기 좋다고 말한다.[^151]

3.5 Dart를 알고 나서 Flutter 기본 코드 다시 읽기: “전부 클래스 + 키밸류” 관점[^152]

📸 1:15:20

Dart 학습 후 다시 main.dart를 보면:

  • main()에서 Flutter 내장 함수 runApp()을 호출한다.[^152]
  • StatelessWidget/StatefulWidget은 Flutter 팀이 제공한 클래스를 상속해 기능을 “한 줄로 가져다 쓰는” 방식이며, 상속은 다른 클래스 내용을 내 클래스로 가져오는 것이라고 설명한다.[^153]
  • MaterialApp, ThemeData, Scaffold, AppBar, body 등도 전부 클래스이고, 속성들이 키:값 형태로 이어진다는 점을 강조한다.[^154]

결론적으로 Flutter UI는 “키값에 무엇을 넣으면 어떤 UI/기능이 되는지”를 문서/AI로 확인하며 조립하는 방식이며, 이제 코드가 “할 만하게” 느껴질 것이라고 말한다.[^155]

3.6 페이지/폴더 구조 만들기: pages/index_page.dart + 단축 생성(STF)[^156]

📸 1:18:05

기존 MyHomePage 부분을 정리하고, lib 폴더가 1차원으로 파일이 많아지면 보기 힘들므로 디렉토리로 관리하자고 제안한다.[^156]

  • lib/pages/ 디렉토리 생성[^157]
  • index_page.dart 생성[^157]
  • Android Studio에서 stf를 입력해 StatefulWidget 템플릿을 자동 생성하고 클래스명은 IndexPage처럼 대문자로 시작한다고 설명한다.[^158]
  • material.dart 임포트를 추가한다.[^159]
  • main.dart의 home을 IndexPage()로 바꾸어 첫 화면을 교체한다.[^160]

실행하면 Placeholder 수준의 화면이 뜨며, 이후 디자인/UI를 넣어갈 것이라고 말한다.[^161]

또한 AI로 UI를 빠르게 뽑을 수 있는 시대지만, 유지보수/협업/소통을 위해 개발자가 기본 원리는 알아야 한다고 강조한다.[^162]

3.7 기본 위젯과 레이아웃: Scaffold/Container/Column/Row, 정렬 축(Main/Cross), 이미지, 텍스트 스타일, 패딩/사이즈박스, 입력창, 버튼[^185]

📸 1:21:45

강사는 위젯 소개를 노션/PDF 자료와 함께 진행하며, Flutter에서 앱 화면을 구성하는 대표 위젯들을 설명·실습한다.[^185]

3.7.1 Scaffold: 앱 기본 골격(건물 “거푸집” 비유)[^186]

Scaffold는 AppBar, Body, Drawer(슬라이드 메뉴), BottomNavigationBar, FloatingActionButton 등 앱에서 흔히 쓰는 기본 요소를 지원하는 “틀”이라고 설명한다.[^186] 구글에서 scaffold 뜻을 찾아보면 건물의 거푸집/기본 틀 같은 의미이며, Flutter는 기능을 제공해두고 “쓰고 싶으면 적고, 안 쓰면 안 적으면 된다”는 철학이라 개발 속도가 빠를 수 있다고 말한다.[^187]

3.7.2 Container: 네모 박스(웹의 div 비유)[^188]

Container는 네모 박스이며 웹 개발자에겐 div와 비슷하다고 설명한다.[^188] 박스이므로 width/height, background color 등 조절이 가능하고, UI는 결국 박스를 배치/늘리고 내부에 글자·버튼을 넣어 만든다고 본다.[^188]

3.7.3 위젯/속성은 외우는 게 아니라 “찾아서 쓴다” + 타입 확인[^189]

위젯과 속성은 매우 많아 외우는 것이 아니라 문서/검색/AI로 찾아서 쓰면 된다고 말한다.[^189] 다만 문법은 타입 기반이므로 “문자가 들어가야 하는데 숫자를 넣으면 안 된다”처럼 타입을 파악할 수 있어야 한다고 강조한다.[^190]

3.7.4 Column/Row: 정렬의 핵심, 99.9%는 Column부터 시작[^191]

정렬 위젯인 Column/Row는 매우 중요하며:

  • Row: 가로로 여러 위젯
  • Column: 세로로 여러 위젯[^191]

앱 UI는 대체로 위에서 아래로 내려가기 때문에 페이지 body에 여러 위젯을 넣을 때 99.9%는 Column을 먼저 둔다고 말한다.[^192] 그리고 Column 내부 일부 구간에서 좌우 배치가 필요하면 Row를 넣는 식으로 조립한다고 설명한다.[^192]

3.7.5 Container 속성 힌트 읽기: 자동완성에서 타입/nullable 파악[^193]

Android Studio 자동완성(옵션 목록)을 보면 color, width, height, decoration 등이 나오고, 타입과 nullable 여부도 표시되어 “안 넣어도 되는지(널러블)” 등을 확인할 수 있다고 설명한다.[^193] decoration처럼 또 다른 클래스가 요구되면 그 내부 속성을 다시 찾아가며 구성해야 하며, 결국 이 정보를 제공하는 공식 문서가 중요하다고 연결한다.[^194]

3.7.6 화면 크기 대응: 고정 px가 아니라 double.infinity 등 반응형 사고[^195]

Container를 300/400 같은 고정 크기로 만들면 폰 사이즈가 다양한 현실에서 빈 공간이 생길 수 있다고 경고한다.[^195] 그래서 width/height에 double.infinity를 주어 가능한 영역을 채우도록 만들 수 있다고 시연한다.[^195]

3.7.7 Column 정렬 축 개념: MainAxis vs CrossAxis[^196]

Column은 자식이 “세로로 진행”하므로 그 진행 방향이 MainAxis(주축), 그 직각이 CrossAxis라고 설명한다.[^196] Row는 반대로 가로가 MainAxis이다.[^196] 문서 편집기의 가운데정렬/끝정렬과 유사하게:

  • start/center/end
  • spaceBetween 등 균등 배치
    같은 속성으로 정렬을 조정한다고 설명하고, 직접 center/end/spaceBetween을 바꿔보며 결과를 확인하라고 한다.[^197]

3.7.8 Image.network: 네트워크 이미지 표시 + 크기 조절[^198]

Image.network(url)로 이미지 주소를 넣어 표시할 수 있고, width/height로 크기 조절도 가능하다고 보여준다.[^198]

3.7.9 Text 스타일: TextStyle로 글자 크기/색/굵기 + “반복 스타일은 변수로 분리”[^199]

“텍스트 글자 크기/색” 같은 것은 GPT에 물어보면 style: TextStyle(...)로 알려준다고 보여주며, 실제로 color, fontWeight, fontSize 등을 적용한다.[^199]

하지만 같은 스타일을 여러 텍스트에 적용하려면 반복 작성이 생기므로, TextStyle ts1 = TextStyle(...);처럼 빌드 상단에 변수로 빼서 재사용하라고 조언한다.[^200] 웹의 CSS 클래스처럼 Flutter는 코드 레벨에서 스타일 데이터를 변수로 관리하는 관점이라고 설명한다.[^200]

강사는 “언어 자체보다 Flutter 개발을 많이 해봐야 한다”는 메시지를 재차 강조하며, 현업 개발자도 공부를 끝내고 개발하는 것이 아니라 “만들면서 공부한다”고 말한다.[^201]

3.7.10 간격 주기: Padding vs SizedBox + 단축(Alt+Enter) 활용[^202]

위젯 사이 간격을 줄 때:

  • Padding: 위젯을 감싸 투명한 튜브를 끼운다는 비유로 설명한다.[^202]
  • SizedBox: 빈 공간만 차지하는 박스로 빠르게 간격을 준다.[^203]

단축키(Windows 기준 Alt+Enter)로 위젯을 Padding으로 감싸는 등 IDE 지원을 활용할 수 있다고 보여준다.[^202]

3.7.11 Row 배치: mainAxisAlignment로 가운데/양끝 배치 패턴[^204]

Row에서 텍스트들을 옆으로 나열하고, mainAxisAlignment: MainAxisAlignment.center 또는 spaceBetween으로 가운데/양끝 배치를 구현하는 패턴이 메뉴/버튼 배치에서 자주 쓰인다고 설명한다.[^204]

3.7.12 TextFormField/TextField: 입력 이벤트(onChanged)와 컨트롤러(TextEditingController)[^205]

텍스트 입력 위젯을 추가하고, 에뮬레이터 키보드로 입력이 가능함을 시연한다.[^205]

  • onChanged는 문자 변경마다 호출되어 값을 출력(print)할 수 있다.[^206]
  • 실무에서는 TextEditingController를 더 많이 쓰며, 컨트롤러로 값을 저장하고 버튼 클릭 시 접근해 꺼내는 패턴을 설명한다.[^207]

3.7.13 버튼(ElevatedButton)과 입력값 접근 예시[^208]

ElevatedButton(onPressed: ..., child: Text('버튼1')) 형태로 버튼을 만들고, 눌렀을 때 컨트롤러의 텍스트를 읽어 출력하거나 로직에 사용할 수 있음을 보여준다.[^208]

3.7.14 상태(State)와 setState: “데이터 변경 + 리빌드”가 핵심[^220]

강의는 “버튼을 눌렀을 때 텍스트(안녕→헬로)를 바꿔보자”는 실습으로 상태 개념을 설명한다.[^220]

  1. 처음엔 텍스트가 코드에 하드코딩되어 있어 버튼을 눌러도 UI가 바뀔 수 없음을 지적한다.[^220]
  2. 텍스트 값을 String helloText = '안녕'; 같은 변수로 빼고, 버튼에서 helloText = '헬로';로 바꾸면 데이터는 바뀌지만 UI는 그대로임을 보여준다(콘솔 print로 값 변경은 확인되지만 화면은 안 바뀜).[^221]
  3. 이유: 프론트(UI)는 “데이터가 바뀌면 UI도 바뀔 것”이라는 개발자 생각과 달리, 실제로는 UI를 다시 그려야 한다고 강조한다.[^222]
  4. 해결: setState(() { helloText = '헬로'; });로 상태 변경을 감싸면 “값 변경 + 다시 그리기”가 수행되어 UI가 갱신된다.[^228]

이 개념은 React의 state와 동일한 계열로 비유하며, Flutter는 setState, React는 useState 같은 메커니즘이라고 설명한다.[^223]

또한 텍스트뿐 아니라 이미지 크기 같은 UI 속성도 전역 변수로 빼고 setState로 변경하면 즉시 UI가 바뀐다고 시연한다.[^229] 결론적으로 “UI에 반영되어야 하는 값은 상태로 빼고 setState로 변경한다”가 핵심이라고 정리한다.[^230]

강사는 이번 파트를 정리하며:

  • 페이지 만들기
  • 위젯 몇 개 직접 사용
  • Column/Row로 정렬
  • 전역 변수 + setState로 실시간 UI 변경
    을 수행했고, 다음은 REST API로 서버에서 데이터를 받아 보여주는 것을 하겠다고 예고한다.[^231]

3.8 REST API + HTTP 통신: 패키지 추가, 요청 타이밍(initState), Future/async/await, JSON decode, setState 반영[^248]

📸 1:49:09

강사는 앱이 서비스가 되려면 서버/DB가 필수이며, 앱만으로는 다른 폰에서 로그인해도 데이터가 없고 타인의 데이터를 보려면 서버가 필요하다고 말한다.[^248] 프런트엔드의 중요한 역할이 서버에 요청해 데이터를 불러와 UI에 보여주는 것이라며 REST API를 다룬다.[^249]

3.8.1 REST API 개념: URL 주소로 데이터 송수신[^250]

REST는 DB에서 정보를 주고받는 방식, API는 프로그램 간 연결 매개체라고 설명하며, REST API는 앱(Flutter)과 DB 사이에 백엔드 서버(URL)를 두고 그 주소로 데이터 통신하는 것이라고 정리한다.[^250]

3.8.2 실습용 API: JSONPlaceholder (todos)[^251]

학습용 무료 Fake REST API인 JSONPlaceholder를 소개하고, /todos/1로 단일 데이터, /todos/2로 다른 데이터, /todos로 200개 목록을 받을 수 있음을 보여준다.[^251]
이때 받는 데이터는 JSON이며 “문자열 기반 데이터”지만, 나중에 특정 타입(List/Map 등)으로 변환해 쓸 수 있다고 설명한다.[^252]

3.8.3 TodoPage 생성 + Navigator.push로 페이지 이동[^254]

todo_page.dart를 만들고 TodoPage(Stateful) + Scaffold/AppBar/Column/Center/Text로 기본 UI를 만든다.[^254]
IndexPage에서 버튼을 만들어 Navigator.push(context, MaterialPageRoute(builder: (_) => TodoPage())) 같은 방식으로 이동한다.[^255]

강사는 push는 기존 페이지 위에 쌓는 스택 구조라고 설명하며, 너무 많이 쌓이면 앱이 무거워질 수 있으니 라우팅 전략(예: 채팅방 들어갔다 나오는 흐름처럼)을 잘 설계해야 한다고 조언한다.[^256]

3.8.4 “요청을 언제 할 것인가”: build가 아니라 initState(라이프사이클)[^257]

서버 요청을 build 메서드에 넣으면 setState로 리빌드될 때마다 요청이 반복되어 비효율/버그가 될 수 있다고 경고한다.[^257]
앱/위젯에는 생명주기(lifecycle)가 있고, 보여질 때/바뀔 때/사라질 때 특정 함수가 호출되며, 대표적으로 initState()에 초기 서버 요청을 넣는다고 설명한다.[^257]

3.8.5 http 패키지 추가(pub.dev) + 별칭 import[^258]

Flutter에서 REST 호출에 많이 쓰는 패키지로 httpdio가 있는데, 여기서는 http를 사용한다고 한다.[^258]
pub.dev에서 http를 찾아 pubspec.yaml의 dependencies에 추가하고 pub get으로 다운로드하는 과정을 보여준다.[^259]

또한 import 'package:http/http.dart' as http;처럼 별칭을 두는 이유는 get/post/... 같은 함수명이 짧아 다른 함수와 이름 충돌 가능성이 있어 http.get()처럼 점 접근을 권장하기 때문이라고 설명한다.[^260]

3.8.6 Future/async/await: “음식 주문” 비유로 비동기 이해[^261]

http 요청 함수는 Future를 반환하는데, Future는 “지금 당장 결과가 없고 나중에 올 것”이라는 의미로 설명한다.[^261]
“음식 주문하고 바로 나왔냐고 묻는 것”이 Future를 await 없이 다루는 상황이며, 음식을 받으려면 기다려야 하듯이 await로 기다려 결과를 받는다고 비유한다.[^262]
그래서 함수에 async를 붙이고 final response = await http.get(...) 형태로 받은 뒤, response.body가 JSON 문자열이라고 설명한다.[^263]

또한 요청이 안 될 때는 header를 추가해야 하는 경우가 있어 headers를 넣는 수정도 시연한다.[^264]

3.8.7 JSON 문자열 → Map/List 변환: jsonDecode, dynamic, 키 접근[^265]

response.body는 String이라서 곧바로 ['title'] 같은 Map 접근이 안 된다고 지적한다.[^265]
jsonDecode(response.body)를 쓰면 자동으로 적절한 타입(Map/List)으로 변환되며, 반환 타입은 상황에 따라 달라 dynamic으로 본다고 설명한다.[^266]
변환 후 json['title']로 title을 꺼내 출력하는 것을 시연하고, URL의 id를 바꾸면 다른 title이 나오는 것도 확인한다.[^267]

또한 함수 매개변수로 int id를 받아 URL 문자열 보간(.../todos/$id)으로 일반화할 수 있다고 설명한다.[^268]

3.8.8 UI에 반영: String title 상태 + setState로 화면 표시[^269]

받아온 타이틀을 화면에 보여주기 위해:

  • String title = '초기값'; 상태를 만들고[^269]
  • 데이터를 받은 뒤 setState(() { title = json['title']; });로 반영[^269]
  • Text 위젯에서 title을 보여주도록 수정
    하는 방식으로 “배운 것의 조합”으로 구현 가능하다고 강조한다.[^270]

3.9 모델(VO) 클래스로 JSON 매핑: Todo 클래스 + fromJson(factory)로 코드 정리[^302]

📸 2:06:15

강사는 title 하나가 아니라 id/userId/completed 등 필드가 늘어나면 UI 코드에서 일일이 꺼내는 방식이 비효율적이라고 지적한다.[^302] 실제 개발에서는 필드가 40~50개까지 늘 수 있고, 이때 Flutter 문서에서도 “커스텀 오브젝트(모델)로 받자”는 패턴이 있다고 설명한다.[^302]

그래서 lib/vo/(또는 model 폴더) 디렉토리를 만들고 Todo 클래스를 생성한다.[^303]

3.9.1 Todo 필드/생성자 설계[^304]

  • int id
  • int userId
  • String title
  • bool completed
    같은 필드를 선언하고 생성자를 만든다.[^304]
    required로 전부 강제하기보다 기본값을 주어 유동적으로 쓰는 설계가 실무에서 편할 때가 많다고 말한다(회원가입에서 필수 필드만 받는 것처럼).[^305]

3.9.2 fromJson(factory)로 Map→Todo 변환[^306]

핵심은 “JSON(Map)을 Todo 객체로 바꾸는 변환 함수”이며, 보통 Todo.fromJson(Map<String, dynamic> json) 형태로 만든다고 설명한다.[^306]
factory는 재사용/규칙상 붙이는 형태로 소개하고, 내부에서 return Todo(id: json['id'], ... )처럼 값을 매핑한다.[^307]

이 과정은 반복 작업처럼 보일 수 있으나(예전엔 직접 다 쳤다), 요즘은 AI가 생성해도 “이게 Map을 Todo로 바꿔주는 코드”라는 의미를 이해해야 한다고 강조한다.[^308]

3.9.3 UI 코드에서 Todo 객체만 들고 쓰기 + null 처리[^309]

TodoPage 쪽에서는:

  • Todo? todo;처럼 상태로 두고(처음엔 null일 수 있음)[^309]
  • 요청 후 final t = Todo.fromJson(json); setState(() { todo = t; });로 상태 반영[^310]
  • UI에서는 todo?.title ?? '없음'처럼 null-safe 접근을 사용해 로딩/빈 상태를 처리할 수 있다고 설명한다.[^311]

그 결과 title/id/userId/completed 등을 todo?.id 같은 형태로 간단히 출력할 수 있고, 변환 로직을 모델로 옮겨 UI 코드가 정리되는 “개선”이 이루어진다고 정리한다.[^312]

3.9.4 다음 과제 예고: 상태관리(Provider)로 UI와 비즈니스 로직 분리/공유[^313]

강사는 현재 구조의 다음 문제를 제시한다:

  • 다른 위젯/컴포넌트에서도 todo 데이터를 쓰려면 비슷한 코드를 다시 짜야 하는 문제[^313]
  • UI 코드와 데이터 처리(비즈니스 로직)가 섞여 코드가 보기 힘들어지는 문제[^313]

그래서 데이터 공유와 로직 분리를 위한 “상태 관리” 개념(Provider 등)을 다음에 다루겠다고 예고하며 마무리한다.[^314]

4. 핵심 통찰[^6]

  1. Flutter 학습의 출발점은 “위젯 문법 암기”가 아니라 앱 개발 방식의 트레이드오프 이해크로스플랫폼의 구조적 이점을 잡는 것이다.[^12][^25]
  2. Dart는 어려운 문법을 많이 아는 것보다, 데이터/함수/조건/반복/클래스 5요소를 “서비스를 만드는 관점”에서 조합하는 능력이 핵심이다.[^95][^93]
  3. Flutter UI는 클래스(위젯) + 키:값 속성 조합이며, 대부분의 위젯 사용법은 문서/AI로 “찾아 쓰되”, 타입/널러블을 읽는 눈이 있어야 한다.[^154][^193]
  4. 프런트 개발의 본질은 “데이터 변화”가 아니라 리빌드 트리거다. Flutter에서는 setState가 그 트리거이며, UI에 반영될 값은 상태로 관리해야 한다.[^222][^228]
  5. 서버 통신은 언제 호출할지(initState)비동기(Future/await) 가 관건이며, 응답(JSON 문자열)을 파싱(jsonDecode) 하고 상태 반영(setState) 까지 이어져야 화면에 나타난다.[^257][^261][^269]
  6. 데이터가 커질수록 “필드 하나씩 꺼내기”는 붕괴한다. 모델(VO) + fromJson 매핑으로 데이터 구조를 규격화하면 UI 코드가 단순해지고 유지보수성이 올라간다.[^302][^306]
  • 실행 행동(강의가 암묵적으로 권하는 실천)
    • pubspec.yaml 추가 패키지 설치 흐름(pub.dev → dependencies → pub get)을 실제로 반복해 익숙해질 것.[^259]
    • build()에 무거운 로직(서버 호출)을 넣지 말고 initState() 같은 라이프사이클에 배치할 것.[^257]
    • UI에 영향을 주는 값은 전역(상태)로 빼고 setState()로 업데이트하는 패턴을 손에 익힐 것.[^229][^230]
    • JSON 응답은 즉시 화면에 박지 말고, 모델 클래스로 매핑해 “UI/로직 분리”의 기반을 만들 것.[^312][^313]

5. 헷갈리는 용어 정리[^6]

네이티브 앱: 플랫폼 고유 언어/SDK로 각각 개발하는 방식(Java/Kotlin, Swift 등).[^15]
웹뷰(WebView): 앱 내부에서 웹사이트(URL)를 화면 전체에 띄우는 컴포넌트/방식.[^19]
하이브리드 앱(강의 정의): 웹 프런트 코드를 앱 내부에 포함해 웹뷰로 실행하는 방식(깜빡임↓, 웹뷰 한계 존재).[^23]
크로스플랫폼: 코드 1개로 안드로이드/iOS 등을 동시에 개발·배포하는 방식.[^24]
위젯(Widget): Flutter UI를 구성하는 모든 요소(화면의 부품이자 구조 단위).[^7]
Scaffold: AppBar/Body/FAB/BottomNav 등 화면 기본 골격을 제공하는 위젯.[^186]
Hot Reload: 코드를 저장/변경하면 빠르게 UI 변경을 반영해 확인하는 기능.[^50]
StatefulWidget: 상태 변화에 따라 UI를 다시 그릴 수 있는 위젯 타입.[^49]
setState: 상태 변경을 Flutter에 알리고 해당 위젯을 리빌드하게 하는 메서드.[^228]
REST API: URL 주소를 통해 앱과 서버/DB가 데이터를 주고받는 방식(강의에서는 URL 자체를 강조).[^250]
http 패키지: Flutter/Dart에서 HTTP 요청을 보내기 위한 패키지(pub.dev에서 설치).[^258]
Future / async / await: 비동기 처리(결과가 나중에 오는 작업을 기다려 받는 구조).[^261][^262]
JSON: 문자열 기반 데이터 포맷이며 Map/List 등으로 변환해 사용.[^252][^265]
모델/VO(Value Object): 서버에서 받은 데이터를 앱 내부에서 규격화해 표현하는 클래스(예: Todo).[^302][^304]
fromJson: JSON(Map)을 모델 객체로 변환하는 관례적 메서드/팩토리 생성자 패턴.[^306]


참고(콘텐츠 정보)[^1]

  • 제목: Flutter 입문 2시간 무료강의 - 모바일 앱 개발 실습 포함 | (주)올리고컴퍼니 기술이사 홍정민[^1]
  • 채널: 메타코드M[^1]
  • 길이: 135분 7초[^1]
  • 링크: https://www.youtube.com/watch?v=mOtWvKkvC7A[^1]

[^1]: @[00:02]~ "Flutter 입문 2시간 무료강의..." 영상 전체(메타코드M). [^2]: @[00:04] "키사에서 진행하는 웹테크 미드업... 플러터 강의를 맡게 된 홍정민..." [^3]: @[00:14]~@[00:24] 올리고컴퍼니 기술이사/개발총괄, K-디지털 강의 진행 소개. [^4]: @[00:36] "현업의... 실무적인 기술들을 최대한... 전달" [^5]: @[01:02]~@[01:12] PDF + 노션 자료 안내. [^6]: @[01:12]~@[01:26] 코드 중심 진행, 개념은 자료로 보완. [^7]: @[01:40]~@[02:08] 목차: 모바일 앱 방식, Dart, 위젯, 상태관리, REST/HTTP, Provider 등. [^8]: @[02:15]~@[02:23] 순서는 유동적으로 진행. [^12]: @[02:35]~@[02:57] 모바일 OS(안드로이드/iOS)와 앱 정의. [^13]: @[03:23]~@[03:28] 네이티브/웹/하이브리드/크로스플랫폼 4가지 소개. [^14]: @[03:06]~@[03:17] 플랫폼별 언어/패턴 차이로 인한 개발 방식 차이. [^15]: @[03:34]~@[03:47] 네이티브 정의와 예시 언어. [^16]: @[03:49]~@[03:55] 네이티브 장점(성능/반응성)과 단점(코드베이스 2개). [^17]: @[04:04]~@[04:10] 인력 두 배 필요 문제. [^18]: @[04:22]~@[04:30] 네이티브 적합 경우/요즘 폰 성능으로 타방식도 잘 돌아감. [^19]: @[04:36]~@[04:54] 웹/웹뷰 방식 설명. [^20]: @[04:54]~@[05:12] 웹 장점: 배포 빠름, 딥한 앱 공부 불필요. [^21]: @[05:16]~@[05:34] 웹 단점: 웹처럼 보임(깜빡임/전환/애니메이션 차이). [^22]: @[05:39]~@[05:57] 웹 적합: 컨텐츠 중심, 빠른 배포. [^23]: @[06:01]~@[06:58] 하이브리드 정의, 깜빡임 없음/웹뷰 성능 한계. [^24]: @[07:09]~@[08:29] React Native 크로스플랫폼, 장점/단점(분기, 복잡 기능). [^25]: @[08:45]~@[09:26] Flutter 발표, Dart, “흰 도화지” 비유, 멀티플랫폼 지향. [^26]: @[09:39]~@[09:57] 강사 개인 경험: Flutter가 쉽고 커뮤니티 좋음, 주력 사용. [^27]: @[10:13]~@[10:31] Android Studio로 기본 원리 학습, AI 도구는 이후 활용. [^28]: @[10:58]~@[11:11] 메모장 개발은 힘듦, IDE 필요. [^29]: @[11:26]~@[11:44] Flutter 설치/환경변수/플러그인 설치 흐름. [^30]: @[16:23]~@[16:30] flutter doctor를 “의사처럼 진단” 비유. [^31]: @[14:03]~@[14:26] GPT 의존보다 공식문서 기반 원리 이해 강조. [^33]: @[13:13]~@[13:26] flutter/bin 경로와 환경변수 설정 필요. [^34]: @[14:56]~@[15:49] Windows 환경변수(Path) 편집 과정. [^35]: @[16:12]~@[16:54] CMD에서 flutter 확인, android licenses 명령 안내. [^36]: @[17:19]~@[17:55] Android Studio 플러그인(Flutter) 설치/재시작. [^37]: @[17:59]~@[18:16] New Project(네이티브) vs New Flutter Project 구분. [^38]: @[18:23]~@[18:34] Flutter SDK 경로 지정(Flutter 폴더까지만). [^39]: @[18:47]~@[19:14] 프로젝트명 소문자+언더스코어, 대문자 에러 가능. [^40]: @[19:30]~@[20:46] 조직명/패키지명 고유성, 스토어 중복 불가, 노출됨. [^41]: @[21:13]~@[21:51] Android/iOS만 체크, 나머지 플랫폼은 지원 미흡 언급. [^42]: @[22:30]~@[23:06] 실행 방법: 에뮬레이터 vs 실기기 USB. [^43]: @[23:06]~@[23:27] Device Manager에서 디바이스 선택/생성. [^44]: @[24:04]~@[24:15] 에뮬레이터 외부창 설정(체크 해제) 안내. [^45]: @[24:25]~@[24:38] 에뮬레이터 사이즈 조절 안내. [^46]: @[25:10]~@[25:22] 첫 빌드 3~5분 걸릴 수 있음. [^47]: @[25:31]~@[25:55] 프로젝트 구조: android/ios, lib/main.dart. [^48]: @[27:52]~@[28:00] 앱 실행 시 main 함수 실행. [^49]: @[28:00]~@[28:58] 위젯 구조(Stateless/Stateful) 훑기. [^50]: @[28:10]~@[28:23] 색 변경 즉시 반영=Hot Reload. [^51]: @[29:26]~@[29:59] Scaffold/AppBar/FAB 삭제 시 즉시 반영 시연. [^52]: @[30:07]~@[30:15] 다음으로 Dart 언어 학습 연결. [^86]: @[30:19]~@[30:45] Dart 학습 시작, 초심자 맞춤 설명 예고. [^93]: @[30:53]~@[31:15] 언어는 서비스 만들기 위한 수단, 먼저 생산적 개발. [^95]: @[31:21]~@[31:38] 언어 핵심 5요소: 데이터/함수/조건/반복/클래스. [^96]: @[31:46]~@[31:58] 데이터 변환=로직 관점. [^97]: @[32:00]~@[32:06] 타입 종류(숫자/문자/bool/list/map). [^98]: @[32:08]~@[32:58] 단일 vs 복수(List/Map), 인덱스 vs 키 접근. [^99]: @[35:50]~@[36:27] DartPad 실행, hello 출력. [^100]: @[36:35]~@[37:19] int 선언/타입 일치 설명. [^101]: @[37:31]~@[38:06] String 선언/따옴표/print 확인. [^102]: @[38:08]~@[38:31] bool은 true/false만, 이지선다 상황. [^103]: @[38:37]~@[38:46] double 소수점 예시. [^104]: @[38:51]~@[39:26] List<타입> 비유(트럭/짐). [^105]: @[39:39]~@[39:46] List에 숫자 넣으면 에러. [^106]: @[39:57]~@[40:42] 인덱스 0부터, 버스 좌석번호 비유. [^107]: @[40:47]~@[41:05] 인덱스 범위 벗어나면 에러, JS와 차이. [^108]: @[41:14]~@[44:13] Map<키,값> 타입, 키는 String 권장. [^109]: @[44:35]~@[45:03] 실무 데이터 혼합→Map<String,dynamic> 패턴. [^110]: @[45:12]~@[46:02] Map 키 접근/중첩 리스트 인덱스 접근 예시. [^111]: @[41:27]~@[41:54] var/dynamic 도입. [^112]: @[42:00]~@[42:27] var: 최초 할당 시 타입 결정 후 고정. [^113]: @[42:49]~@[42:58] dynamic: 타입 자유롭게 변경 가능. [^114]: @[43:01]~@[43:20] 실무에서는 dynamic 잘 안 씀, var 주로. [^115]: @[46:04]~@[47:20] Null safety 개념과 목적. [^116]: @[46:49]~@[47:11] null 비유(박스에 없음). [^117]: @[47:30]~@[47:43] 타입에 ? 붙여 nullable 명시. [^118]: @[47:51]~@[48:17] 초기값 지정, 공백 vs null 차이. [^119]: @[48:23]~@[48:50] late 의미와 주의(세팅 안 하면 에러). [^120]: @[33:10]~@[33:30] 함수 정의(로직에 이름), 운전 경로 비유. [^121]: @[49:48]~@[50:48] 함수 선언/호출 개념. [^122]: @[50:55]~@[51:32] 매개변수 필요성(고정 값의 한계). [^123]: @[51:42]~@[52:49] 위치 매개변수, 인자 개수/순서 불일치 에러. [^124]: @[53:03]~@[55:27] return/반환 타입 일치, “받아야 UI 처리 가능” 강조. [^125]: @[35:14]~@[35:44] 클래스=규격화된 복합 데이터 타입 관점. [^126]: @[55:34]~@[56:16] named parameter(중괄호) 도입. [^127]: @[57:15]~@[57:27] 매개변수 많으면 named가 유리. [^128]: @[56:04]~@[56:34] named에서 ?, 기본값, required 설명. [^129]: @[56:49]~@[57:08] named 호출 형태(number1: 10). [^130]: @[57:43]~@[58:17] if 조건식은 bool만 가능, true/false. [^131]: @[58:51]~@[59:54] score 비교로 조건식이 true/false 리턴 설명. [^132]: @[01:00:12]~@[01:00:23] else 분기 설명. [^133]: @[01:00:38]~@[01:00:59] else if 추가 조건. [^134]: @[01:01:20]~@[01:01:45] if 체인: 첫 true면 뒤 안 보고 탈출. [^135]: @[01:01:50]~@[01:02:03] 조건식은 자유롭고, 실무에선 한 데이터에 조건 많음. [^136]: @[01:02:12]~@[01:02:56] for문 예시(0~99 출력). [^137]: @[01:03:00]~@[01:03:55] for 프로세스(초기→조건→실행→증가→탈출) 설명. [^138]: @[01:04:07]~@[01:05:19] 리스트+length 기반 순회 예시. [^139]: @[01:05:31]~@[01:05:58] for-in 패턴과 원리 설명. [^140]: @[35:02]~@[35:44] 클래스 설명(규격화된 여러 값 타입). [^141]: @[35:25]~@[35:32] 클래스는 정해진 항목만. [^142]: @[01:06:37]~@[01:07:17] 변수로 흩뿌리기/Map의 기준 없음 문제. [^143]: @[01:07:17]~@[01:07:19] 그래서 클래스를 쓰자. [^144]: @[01:07:25]~@[01:08:31] Animal 클래스/필드/생성자 개념. [^145]: @[01:09:03]~@[01:09:35] this로 필드 구분. [^146]: @[01:09:40]~@[01:09:52] null safety 처리 언급. [^147]: @[01:09:58]~@[01:10:45] 인스턴스 생성/필드 접근. [^148]: @[01:11:06]~@[01:11:24] 객체지향 직관(속성 추가는 클래스에서). [^149]: @[01:11:33]~@[01:12:31] 클래스 메서드 + 문자열 보간 예시. [^150]: @[01:12:32]~@[01:13:07] 메서드 호출/유지보수 이점 설명. [^151]: @[01:13:17]~@[01:14:30] 네임드 컨스트럭터/키밸류 생성 방식 가독성. [^152]: @[01:15:20]~@[01:15:33] runApp 내장함수, 공식문서 필요. [^153]: @[01:15:49]~@[01:16:09] 상속 설명, StatelessWidget 기능 가져오기. [^154]: @[01:16:10]~@[01:17:23] MaterialApp/ThemeData/Scaffold/AppBar 키밸류 구조. [^155]: @[01:17:36]~@[01:17:40] Dart 알고 나니 Flutter 코드가 할 만함. [^156]: @[01:18:05]~@[01:18:16] 기존 코드 정리, 새 페이지 만들기. [^157]: @[01:18:19]~@[01:19:09] pages 디렉토리/ index_page.dart 생성. [^158]: @[01:19:16]~@[01:19:44] stf 템플릿 생성, IndexPage 클래스. [^159]: @[01:19:44]~@[01:19:53] material import. [^160]: @[01:20:01]~@[01:20:07] home을 IndexPage로 설정. [^161]: @[01:20:20]~@[01:20:26] Placeholder 설명. [^162]: @[01:20:42]~@[01:21:17] AI로 UI 생성 가능하지만 기본 이해/소통 필요. [^185]: @[01:21:45]~@[01:24:10] 위젯 소개(Scaffold, Container 등) 시작. [^186]: @[01:21:48]~@[01:22:18] Scaffold가 지원하는 요소들 설명. [^187]: @[01:22:23]~@[01:22:45] Scaffold=거푸집, 쓰고 싶으면 적는다. [^188]: @[01:22:47]~@[01:23:12] Container=박스, div 비유, UI 구성 관점. [^189]: @[01:23:19]~@[01:23:36] 위젯/속성은 찾아서 쓴다. [^190]: @[01:23:36]~@[01:23:56] 타입 기반 문법 이해 필요(문자/숫자). [^191]: @[01:24:10]~@[01:24:27] Column/Row 정의와 중요성. [^192]: @[01:24:29]~@[01:24:56] 99.9%는 Column부터, 부분은 Row. [^193]: @[01:25:34]~@[01:26:08] 자동완성에서 속성/타입/널러블 확인. [^194]: @[01:26:19]~@[01:26:40] 속성 내부도 찾아봐야, 문서 중요. [^195]: @[01:27:39]~@[01:28:26] 고정 크기 지양, double.infinity로 대응. [^196]: @[01:29:49]~@[01:30:23] Column/Row 축(Main/Cross) 설명. [^197]: @[01:30:41]~@[01:31:58] mainAxisAlignment center/end/spaceBetween 실습. [^198]: @[01:32:02]~@[01:33:15] Image.network + width/height 조절. [^199]: @[01:33:24]~@[01:34:38] GPT로 TextStyle 방법 확인 후 적용. [^200]: @[01:34:44]~@[01:35:41] TextStyle 변수로 분리해 재사용. [^201]: @[01:35:54]~@[01:36:14] 공부 끝내고 개발X, 만들면서 공부. [^202]: @[01:36:26]~@[01:37:22] Padding 감싸기(Alt+Enter), 튜브 비유. [^203]: @[01:37:22]~@[01:37:39] SizedBox로 간격 주기 선호. [^204]: @[01:38:03]~@[01:39:10] Row 정렬(mainAxisAlignment) 패턴. [^205]: @[01:39:19]~@[01:39:46] TextFormField 입력/키보드. [^206]: @[01:39:46]~@[01:40:18] onChanged로 입력값 출력. [^207]: @[01:40:25]~@[01:40:47] TextEditingController 소개(버튼 시점에 값 꺼냄). [^208]: @[01:41:46]~@[01:42:49] ElevatedButton 구조, 컨트롤러 값 접근. [^220]: @[01:43:12]~@[01:43:22] 버튼 눌러 안녕→헬로 변경 목표. [^221]: @[01:44:29]~@[01:45:19] 변수로 바꿔도 UI는 안 바뀜(콘솔만 변경). [^222]: @[01:45:23]~@[01:45:53] “데이터 바뀌면 UI도 바뀔 것”은 착각, 리빌드 필요. [^223]: @[01:46:05]~@[01:46:16] React(useState) vs Flutter(setState) 비유. [^228]: @[01:46:19]~@[01:46:58] setState로 변경+다시 그림→UI 갱신. [^229]: @[01:47:08]~@[01:47:56] 이미지 크기도 상태로 빼고 setState로 변경 시 즉시 반영. [^230]: @[01:47:41]~@[01:48:06] “바뀌어야 될 요소를 상태로 빼고 setState로 바꾼다” 정리. [^231]: @[01:48:09]~@[01:48:51] 이번 파트 정리 + 다음 REST API 예고. [^248]: @[01:49:09]~@[01:49:40] 앱 서비스에는 서버/DB 필요 강조. [^249]: @[01:49:42]~@[01:49:53] 프런트의 역할: 데이터 요청/표시. [^250]: @[01:50:04]~@[01:50:43] REST/API 정의, URL 주소 강조. [^251]: @[01:50:58]~@[01:51:54] JSONPlaceholder 소개, /todos/1, /todos 등. [^252]: @[01:51:54]~@[01:52:22] JSON은 문자 기반, Map/List로 변환 가능. [^253]: @[01:57:21]~@[01:57:45] http vs dio 언급, http 사용. [^254]: @[01:52:29]~@[01:53:35] TodoPage 생성, 기본 UI 구성. [^255]: @[01:53:44]~@[01:54:45] Navigator.push로 이동 구현/시연. [^256]: @[01:54:55]~@[01:55:23] push 스택 구조, 라우팅 전략 필요. [^257]: @[01:55:49]~@[01:56:44] build에서 요청하면 리빌드마다 호출, initState/lifecycle로 해결. [^258]: @[01:57:21]~@[01:57:49] http 패키지 사용 방향. [^259]: @[01:58:05]~@[01:58:52] pub.dev에서 http 찾아 pubspec에 추가, pub get. [^260]: @[01:59:28]~@[01:59:47] import 별칭(as http) 이유(함수명 충돌 방지). [^261]: @[02:00:10]~@[02:00:28] Future=비동기, Future 나오면 비동기. [^262]: @[02:00:32]~@[02:00:58] 음식 주문 비유, await로 기다림. [^263]: @[02:01:01]~@[02:01:23] async/await + response.body(JSON 문자열) 설명. [^264]: @[02:01:44]~@[02:02:36] 요청 안 될 때 headers 추가 필요 언급/수정. [^265]: @[02:03:01]~@[02:03:19] body는 String이라 title 접근 불가. [^266]: @[02:03:20]~@[02:03:37] jsonDecode로 타입 변환, 반환 dynamic. [^267]: @[02:03:44]~@[02:04:11] json['title'] 출력, id 변경 시 다른 값. [^268]: @[02:04:18]~@[02:04:45] id를 매개변수로 받아 URL 보간. [^269]: @[02:05:01]~@[02:05:29] title 상태 + setState로 UI 반영. [^270]: @[02:05:34]~@[02:05:37] 배운 것 조합으로 구현 가능 강조. [^285]: @[02:00:03]~@[02:01:06] http.get + async/await 코드 흐름. [^302]: @[02:06:15]~@[02:06:41] 필드 많아지면 비효율, 모델(VO)로 개선 필요. [^303]: @[02:06:52]~@[02:07:05] vo 디렉토리 생성, Todo 클래스 만들기. [^304]: @[02:07:19]~@[02:07:57] Todo 필드(id/title/completed 등) 선언. [^305]: @[02:08:00]~@[02:08:10] required 강제보다 기본값으로 유동성. [^306]: @[02:09:09]~@[02:09:21] fromJson 패턴, Map<String,dynamic> 받아 객체로. [^307]: @[02:09:35]~@[02:10:18] factory Todo.fromJson 구현(키 매핑). [^308]: @[02:10:23]~@[02:10:39] AI가 만들어도 의미 이해가 핵심. [^309]: @[02:11:03]~@[02:11:26] Todo? 상태로 보관, null 가능. [^310]: @[02:11:30]~@[02:11:52] Todo.fromJson 후 setState로 todo 갱신. [^311]: @[02:12:15]~@[02:12:27] null-safe 접근(todo?.title ?? '없음')으로 로딩/빈값 처리. [^312]: @[02:13:21]~@[02:13:34] 객체로 받으면 UI 코드가 단순, 변환 로직 분리 효과. [^313]: @[02:14:11]~@[02:14:41] 다른 위젯에서 공유/코드 중복, UI와 로직 섞임 문제 제시. [^314]: @[02:14:46]~@[02:15:06] 다음: 상태관리로 분리/공유(Provider) 예고.

← 프로젝트에서 보기