https://www.youtube.com/watch?v=ZWLoYecgzTU
1. 이건 꼭 알아야 한다^1
[? 질문] Flutter 프로젝트를 만들면 자동 생성되는 “카운터 앱” 대신, 내가 원하는 앱(주사위 앱)을 어떻게 빠르게 구성할 수 있는가^2
[= 답] 자동 생성된 코드를 과감히 삭제한 뒤, 홈 화면 위젯을 새로 만들고(MaterialApp → home 연결), Scaffold + Image.asset으로 UI를 구성하면 된다.[^2][^8]
[? 질문] Flutter에서 화면(UI)을 만드는 기본 단위인 위젯은 무엇이며, 상태(State)가 왜 중요한가[^6]
[= 답] 화면의 글자/색/버튼 등 보이는 모든 요소가 위젯이고, UI 위젯은 **StatelessWidget(상태 없음)**과 **StatefulWidget(상태 관리 가능)**로 나뉜다. 주사위 숫자처럼 바뀌는 값을 다루려면 StatefulWidget이 필요하다.[^6][^7]
[? 질문] 주사위 이미지를 “탭할 때마다” 1~6 사이 숫자가 바뀌게 하려면 어떤 흐름으로 구현해야 하는가[^20]
[= 답] (1) 숫자를 변수로 관리하고 이미지 경로에 반영한 뒤[^18] (2) GestureDetector의 onTap에서 setState로 변수를 변경하여 빌드를 다시 실행하고[^23] (3) Random().nextInt(6)+1로 1~6 난수를 만들어 대입하면 된다.[^27][^28]
2. 큰 그림^2
이 콘텐츠는 Flutter로 앱을 만들 때 기본 생성되는 카운터 예제를 지우고, 아주 짧은 코드로 주사위(dice) 앱을 만드는 전 과정을 “실습 흐름” 그대로 보여주는 튜토리얼이다.[^2][^24] 프로젝트 구조를 정리하고, 화면 위젯을 만든 다음, 에셋 이미지 등록과 UI 배치, 탭 이벤트 처리, 상태 갱신, 난수 생성까지 한 번에 연결한다.[^10][^21]
- 자동 생성 코드 제거 → 내가 원하는 화면부터 재구성: 기본 카운터 앱 코드를 삭제하고, 별도 screen 폴더와 HomeScreen 파일을 만들어 홈 화면을 직접 구성한다.[^2][^4]
- UI는 Scaffold + Image.asset + Center로 직관적으로 구성: 검정 배경 위에 주사위 이미지를 에셋에서 불러와 중앙 정렬해 표시한다.[^13][^17]
- 상태 변경(setState) + 입력(GestureDetector) + 난수(Random)로 “누를 때마다 바뀌는 주사위” 완성: 탭 이벤트에서 숫자 변수를 업데이트하고, 그 결과 UI 이미지가 즉시 바뀌도록 만든다.[^22][^23]
3. 하나씩 살펴보기^1
3.1 Flutter 기본 생성 앱 확인과 “카운터 앱” 코드 삭제^1
영상은 Flutter 앱을 새로 생성하면 가장 먼저 보게 되는 기본 실행 화면을 보여주며 시작한다.^1 기본 템플릿 앱에는 “플러스(+) 버튼을 누르면 숫자가 계속 올라가는” 카운터 기능이 들어 있는데, 화자는 이를 “굉장히 쓸데없는 카운터 앱”이라고 표현하며, 이번 목표(주사위 앱)와는 무관하니 템플릿 코드를 없애고 처음부터 직접 작성하겠다고 한다.^2
- Flutter 프로젝트 생성 직후에는 기본 앱이 실행되는 상태를 확인할 수 있다.^1
- 기본 앱에서 + 버튼을 누르면 카운터 숫자가 계속 증가한다.^2
- 이번 실습 목표는 카운터가 아니라 더미 주사위 앱이므로, 자동 생성된 코드를 모두 지우고 직접 구현한다.^2
- 실제로 “모두 지우겠다”고 말하며 코드를 삭제하고, 앱에 들어있는 값도 함께 정리한다.[^3]
[!IMPORTANT] 템플릿 제거의 의도
기본 템플릿을 “수정”하는 방식이 아니라, 필요 없는 부분을 통째로 제거하고 앱의 뼈대(MaterialApp, 홈 화면 위젯)부터 다시 세팅하는 흐름을 보여준다.[^2][^8]
3.2 폴더/파일 구조 만들기: screen 폴더와 HomeScreen 파일 생성[^4]
코드를 지운 뒤, 프로젝트 구조를 새로 잡는다.[^4] 화자는 (리…) 폴더에서 우클릭하여 새 디렉터리를 만들고, 그 디렉터리 이름을 screen(스크린)으로 만든다.[^4] 그리고 screen 폴더에서 다시 우클릭하여 새 파일을 만들고, 파일명을 home_screen.dart로 생성한다.[^4]
- (프로젝트 내) 폴더를 우클릭 → 새 디렉터리 생성 →
screen폴더 생성.[^4] screen폴더 우클릭 → 새 파일 생성 →home_screen.dart생성.[^4]
이 파일에는 “가장 기본적으로 넣어줘야 되는 material 관련(기본 뼈대)”을 작성하겠다고 안내한다.[^5]
3.3 위젯 개념 정리: UI는 모두 위젯, Stateless vs Stateful[^6]
화자는 곧바로 “위젯”이 무엇인지 짧게 정의한다.[^6]
- [h 위젯은 Flutter에서 화면에 보여지는 모든 요소를 뜻한다.]
화면의 글자, 색깔, 버튼 등 “화면에 있는 모든 것”이 위젯으로 이루어진다고 설명한다.[^6]
또한 UI를 만드는 위젯이 크게 두 가지로 나뉜다고 한다.[^7]
- StatelessWidget: 상태 관리를 하지 못하는 위젯.[^7]
- StatefulWidget: 상태 관리를 할 수 있는 위젯.[^7]
이 차이가 정확히 궁금하면 설명란에 있는 “무려 30시간 분량의 플러터 왕초보 강의”를 참고하라고 연결한다.[^8]
3.4 HomeScreen을 StatefulWidget으로 생성하고, Container → Scaffold로 변경[^9]
이제 home_screen.dart에서 홈 화면 위젯을 만든다.[^9] 화자는 홈 스크린을 StatefulWidget으로 만들겠다고 말한다.[^9]
구체적 생성 방법으로, 코드 에디터에서 키워드 stf를 입력하고 엔터를 치면, “간단하게 두 개의 클래스”로 이루어진 StatefulWidget 템플릿이 만들어진다고 설명한다.[^9]
stf+ Enter → StatefulWidget 코드 스니펫 생성(두 개 클래스 구조).[^9]- 위젯 이름은
HomeScreen으로 짓는다.[^10]
그리고 기본으로 생성된(혹은 작성된) Container를 Scaffold로 변경한다고 말하며, 이 단계가 “이게 다”라고 할 만큼 매우 간단하다고 강조한다.[^11]
Container→Scaffold로 변경.[^11]
[!TIP] Scaffold를 쓰는 이유(영상 흐름상 의미)
이후에 배경색(backgroundColor)과 본문(body)를 채우는 방식으로 화면을 구성하기 위해, Flutter의 기본 화면 구조 위젯인 Scaffold를 사용한다.[^13][^14]
3.5 main.dart에서 MaterialApp과 home 연결: HomeScreen 띄우기[^12]
HomeScreen이 준비되면 main.dart로 이동해 앱의 루트를 설정한다.[^12] 화자는 MaterialApp을 넣어주고, 그 home에 HomeScreen을 연결하겠다고 설명한다.[^12]
main.dart에서 앱 루트에MaterialApp을 배치한다.[^12]MaterialApp의home:에HomeScreen()을 지정한다.[^12]
이후 앱을 재시작하면 “흰색 화면”이 보이는데, 이것이 방금 만든 HomeScreen의 기본 모습(아직 내용이 없는 상태)이라고 설명한다.[^12][^13]
- 재시작 결과: 흰 화면 표시.[^12]
- 그 흰 화면은 제작한 HomeScreen이 “제시(표시)된” 결과라고 해석해 준다.[^13]
3.6 이미지 에셋 준비와 pubspec.yaml 등록, pub get 실행[^14]
화자는 주사위 이미지를 미리 사용할 수 있도록 이미지들을 assets 폴더 안으로 이동해 두었다고 말한다.[^14] Flutter에서 프로젝트가 에셋 이미지를 쓰려면, 프로젝트 생성 시 자동으로 만들어지는 pubspec.yaml을 수정해 경로를 등록해야 한다고 안내한다.[^15]
- 이미지를
assets폴더로 옮겨 둔다.[^14] - 프로젝트에서 에셋을 쓰려면
pubspec.yaml에 등록이 필요하다.[^15]
구체적으로는 flutter: 섹션 아래에 assets:를 추가하고, 등록하고 싶은 폴더 경로(예: assets/images/)를 넣어주면 그 폴더 안의 모든 이미지를 사용할 수 있다고 설명한다.[^16]
flutter:아래에assets:선언.[^16]- 예시 경로로
assets/images/를 추가하면 해당 폴더의 모든 이미지를 사용 가능.[^16]
설정을 고친 뒤에는 반드시 pub get을 실행해야 한다고 강조한다.[^17]
pubspec.yaml수정 후pub get실행 필수.[^17]
[!WARNING] 에셋 등록 후 “pub get” 누락
화자는 설정을 고친 다음 “펍 겟(pub get)을 꼭 실행”해야 한다고 말한다. 이 단계가 누락되면 에셋을 찾지 못하는 문제가 나기 쉽다는 맥락이다.[^17]
3.7 Scaffold 배경을 검정으로, body에 주사위 이미지 표시(Image.asset)[^18]
pub get이 끝나면 다시 HomeScreen으로 돌아와 UI를 채운다.[^18]
- 먼저
Scaffold의backgroundColor에Colors.black을 넣어 배경을 검정색으로 변경한다.[^18]
Scaffold(backgroundColor: Colors.black, ...)로 검정 배경.[^18]
- 다음으로
body에 이미지를 넣는다.[^19]
이미지는Image위젯을 사용하며, 에셋에서 불러올 것이므로Image.asset(영상에서는 “이미지 점 에셋”)을 사용한다고 설명한다.[^19]
body:에Image.asset(...)배치.[^19]- 괄호 안에 원하는 이미지 위치(경로)를 넣는다.[^20]
화자는 예시로 assets/images/1.png를 넣으면 저장 시 1번 주사위 이미지가 화면에 표시된다고 말한다.[^20]
- 예:
Image.asset('assets/images/1.png')→ 1번 주사위 표시.[^20]
3.8 Center로 이미지 중앙 정렬, 위젯 구성의 직관성 강조[^21]
주사위 이미지를 화면 가운데로 두고 싶으면 Image.asset을 Center 위젯으로 감싸면 된다고 설명한다.[^21]
Center(child: Image.asset(...))→ 중앙 정렬.[^21]
여기서 화자는 본인이 “가운데 정렬하고 싶어서 Center를 썼고, 이미지를 넣고 싶어서 Image.asset을 썼다”고 말하며, Flutter의 UI 구성이 매우 간단하고 직관적이라고 강조한다.[^22]
- 가운데 정렬 목적 →
Center사용.[^22] - 이미지 표시 목적 →
Image.asset사용.[^22] - 전반적으로 “굉장히 간단하고 직관적”이라고 평가.[^22]
3.9 “눌렀을 때 바뀌는 주사위”를 위한 상태 변수 도입(숫자 → 이미지 경로)[^23]
이제 목표를 “주사위를 누를 때마다 새로운 랜덤 숫자의 주사위가 생성되도록” 만드는 것으로 제시한다.[^23]
여기서 핵심은, 화면에 보여지는 숫자(주사위 면)가 고정된 문자열 경로가 아니라 특정 변수 값을 바라보게 만들어야 한다는 점이다.[^23]
- [h 주사위를 누를 때마다 새 숫자가 나오게 하려면, 숫자가 변수가 되어야 한다.]
- 이미지 경로가 그 변수를 반영하도록 구성해야 한다.[^23]
그래서 int number = 1;(영상 발화상 “인차… 넘버는 1”) 같은 변수를 저장해 두고,[^24] 하드코딩했던 1.png 대신 변수 기반 표현(문자열 보간)을 사용하도록 변경한다.[^24]
number변수를 1로 초기화.[^24]- 이미지 경로를
number를 사용하도록 변경.[^24] - 저장하면 “마찬가지로” 1을 표현하는 주사위가 보인다고 확인한다.[^25]
3.10 탭 입력 처리: GestureDetector로 감싸고 onTap에서 동작 연결[^26]
주사위를 눌렀을 때 특정 기능이 실행되게 하기 위해, Image.asset을 GestureDetector 위젯으로 감싼다고 설명한다.[^26]
GestureDetector(child: Image.asset(...))로 감싼다.[^26]onTap파라미터에 함수를 넣는다.[^26]
테스트로 onTap에 print('클릭')을 넣으면, 주사위를 누를 때마다 클릭 출력이 찍히는 것을 볼 수 있다고 한다.[^27] 이를 통해 “onTap 안에서 number 값을 변경하면 화면 이미지를 변경할 수 있다”는 의미라고 해석해 준다.[^27]
onTap: () { print('클릭'); }로 입력 이벤트 확인.[^27]- 이 출력 확인은, 탭 이벤트가 제대로 연결되었음을 보여준다.[^27]
3.11 setState로 상태 변경 → build 재실행 → UI 업데이트(예: number=4)[^28]
이제 print를 삭제하고, 실제로 화면이 바뀌게 만든다.[^28] 화자는 setState를 “빌드 함수를 재실행할 수 있는 함수”라고 설명하면서, 이 함수를 실행하고 그 안에서 변경하고 싶은 값을 지정하면 된다고 말한다.[^28]
setState(() { ... })호출 → build 재실행.[^28]- 그 안에서
number값을 변경.[^28]
예시로 number = 4;로 넣어보고 저장한 뒤 주사위를 눌러보면, 주사위 이미지가 4로 바뀌는 것을 확인할 수 있다고 한다.[^29]
- 탭 →
number가 4로 바뀜 → 주사위가 4로 변경됨.[^29]
3.12 Random으로 1~6 난수 생성: nextInt(6)+1, 변수 대체 후 완성[^30]
고정적으로 4로 바꾸는 법은 배웠으니, 이제 “랜덤하게 생성하고 싶으면 어떻게 해야 할까요”라는 질문을 던진다.[^30]
[? 랜덤하게 주사위 숫자를 만들려면 무엇을 쓰면 되는가]
[= Random 함수를 사용하면 된다] [^31]
구현 흐름은 다음과 같다.
Random()을 사용한다.[^31]newNumber라는 변수에 새로운 숫자를 저장한다.[^32]Random().nextInt(6)로 0~5 범위의 숫자 6개를 랜덤 생성하고,[^33]- 여기에
+ 1을 해서 0~5가 아니라 1~6이 되도록 만든다고 설명한다.[^33]
즉 로직은 “0부터 5”가 나오므로 “+1 해서 1부터 6”으로 보정하는 방식이다.[^33]
그리고 setState 안에서 number = newNumber;처럼 newNumber로 대체해 주면, 저장했을 때 이제는 주사위를 누를 때마다 랜덤으로 새로운 숫자가 생성되는 것을 볼 수 있다고 말한다.[^34]
number에newNumber를 대입하도록 변경.[^34]- 탭할 때마다 1~6 랜덤 변경 확인.[^34]
마지막으로 화자는 “그래서 1부터 6까지 랜덤하게 생성되는 주사위 앱을 만들 수 있었다”고 정리하며, 전체 과정이 직관적이지 않냐고 마무리한다.[^35][^36]
- 1~6 랜덤 주사위 앱 구현 완료.[^35]
- “굉장히 직관적”이라는 소감으로 종료.[^36]
4. 핵심 통찰^2
- [c Flutter 실습은 템플릿을 조금씩 고치는 것보다, 목표 UI에 맞게 뼈대를 다시 세우는 접근이 빠를 때가 있다.] 자동 생성 카운터 앱을 삭제하고 HomeScreen 중심으로 재구성하는 흐름이 그 예다.[^2][^12]
- [h Flutter에서 “UI 변화”는 곧 “상태 변화”이며, 상태 변화는 setState를 통해 build 재실행으로 화면에 반영된다.] 주사위 숫자 변경 → 이미지 변경을 그대로 보여준다.[^28][^29]
onTap에서setState로 값을 바꾼다.[^26][^28]- 화면은 변수 기반(이미지 경로 보간)으로 그 값을 바라보게 한다.[^23][^24]
- [h 에셋 이미지는 pubspec.yaml에 등록하고 pub get을 실행해야 앱에서 사용할 수 있다.] 이 과정을 거친 뒤
Image.asset으로 불러오는 흐름을 제시한다.[^16][^17][^19] - [m 난수 범위는 API 특성을 이해하고 보정해야 한다.]
nextInt(6)이 0~5를 만든다는 점을 전제로+1로 1~6을 만든다.[^33]
참고(콘텐츠 정보)^1
- 제목: 5분만에 배워보는 Flutter 앱개발^1
- 채널: 코드팩토리^1
- 길이: 4분 39초^1
- 링크: https://www.youtube.com/watch?v=ZWLoYecgzTU^1
[^3]: @[00:10] "모두 지우겠습니다" / @[00:16] "지우고 ... 값도 모두 지울게요"
[^4]: @[00:22] "오른쪽 클릭... 새로 만들기 디렉터리... 스크린 폴더... 파일에서 홈_스크린.dart..."
[^5]: @[00:28] "여기에는 ... 가장 기본 ... 메텔..."(material 관련 기본 구성 언급)
[^6]: @[00:39] "위젯은 플러터에서 화면에 보여지는 모든 요소" / @[00:44] "글자... 색깔... 버튼... 다 위젯"
[^7]: @[00:47] "ui를 만드는 위젯은 두가지... 스테이트리스... 스테이트풀"
[^8]: @[01:00] "정확히 궁금... 30시간 분량... 강의" / @[01:22] "메인... 머테리얼 앱..."(MaterialApp 연결 맥락)
[^9]: @[01:07] "홈 스크린에 스테이트 위젯" / @[01:10] "stf... 엔터... 두 개의 클래스"
[^10]: @[01:12] "이름은 ... 홈스크린"
[^11]: @[01:15] "컨테이너를 스케 폴드로 변경" / @[01:17] "이게 다"
[^12]: @[01:22] "메인... 머테리얼 앱" / @[01:25] "home에 ... 홈 스크린" / @[01:29] "재시작하면 ... 흰색 화면"
[^13]: @[01:33] "이 흰색 화면은 ... 홈스크린"
[^14]: @[01:33] "이미지들을 사용할 수 있도록 ... 에세(assets) 폴더 안에다가 이동"
[^15]: @[01:41] "프로젝트 생성할 때 자동으로 생성되는 pubspec.yaml ... 붙여줘야"
[^16]: @[01:49] "flutter 키... assets ... 이미지/ ... 넣어주면 ... 모두 이미지 사용"
[^17]: @[01:59] "pubspec.yaml 고친 다음에는 pub get 꼭 실행"
[^18]: @[02:04] "스케폴드 backgroundColor에 Colors.black"
[^19]: @[02:09] "body에 ... 이미지" / @[02:14] "Image 위젯... Image.asset"
[^20]: @[02:19] "괄호 안에 ... 이미지 위치" / @[02:24] "assets/images/1.png"
[^21]: @[02:36] "중앙 정렬... Center로 감싸"
[^22]: @[02:46] "Center... Image... 굉장히 간단하고 직관적"
[^23]: @[02:55] "주사위를 누를 때마다 ... 랜덤 숫자" / @[02:59] "숫자를 특정 변수를 바라보도록"
[^24]: @[03:03] "int number는 1" / @[03:07] "변수로 변경"
[^25]: @[03:12] "저장... 이를 표현해 주는 주사위"
[^26]: @[03:16] "주사위 눌렀을 때" / @[03:21] "GestureDetector로 감싸" / @[03:25] "onTap"
[^27]: @[03:29] "print... 클릭" / @[03:36] "onTap 안에서 number 값 변경하면 화면 이미지 변경"
[^28]: @[03:41] "프린트 삭제... setState... 빌드 함수를 재실행" / @[03:47] "number는 ..."
[^29]: @[03:53] "눌러보면 ... 4로 변경"
[^30]: @[04:01] "4로 변경하는 법... 랜덤하게 생성 ...?"
[^31]: @[04:06] "Random 함수를 사용"
[^32]: @[04:11] "newNumber에다가 새로운 숫자 저장"
[^33]: @[04:15] "Random().nextInt(6)" / @[04:15] "6개의 숫자" / @[04:15] "+1 해서 0~5가 아닌 1~6"
[^34]: @[04:22] "newNumber로 대체... 누를 때마다 랜덤"
[^35]: @[04:26] "1부터 6까지 랜덤 ... 주사위 앱"
[^36]: @[04:37] "굉장히 직관적이지 않나요"