Chapter04. 스토어 앱 만들기 실습
0️⃣ 실습 개요
개요
이 실습은 Flutter로 아주 기본적인 스토어 앱 화면을 만들어보는 예제다.
현재 코드는
MaterialApp을 루트로 사용하고, Scaffold 안에 Column을 배치한 뒤,위쪽에는 카테고리 메뉴를
Row로 두고 아래에는 상품 이미지를 세로로 2개 배치하는 구조다.🎯 핵심 학습 포인트
- Flutter 앱의 시작점인
main()과runApp()이해하기
StatelessWidget으로 화면 만들기
MaterialApp과Scaffold의 역할 이해하기
Column,Row,Padding,Expanded,SizedBox로 레이아웃 구성하기
Image.asset()으로 로컬 에셋 이미지 출력하기
mainAxisAlignment,flex,fit같은 자주 쓰는 옵션 이해하기
1️⃣ lib/main.dart 실습 코드 전체
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("다시 그려짐");
return MaterialApp(
home: Scaffold(
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(25.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text("Women"),
Text("Kids"),
Text("Shoes"),
Text("Bag"),
],
),
),
Expanded(
flex: 1, // 1/(1+1) 만약 밑에가 3이라면 1/(1+3)
child: Image.asset(
"assets/bag.jpeg",
fit: BoxFit.cover,
),
),
SizedBox(height: 2),
Expanded(
flex: 1, // 1/(1+1) 만약 밑에가 3이라면 3/(1+3)
child: Image.asset(
"assets/cloth.jpeg",
fit: BoxFit.cover,
),
),
],
),
),
);
}
}2️⃣ 코드 실행 흐름 정리
1) 앱 시작
main()은 Flutter 앱의 시작점
runApp(MyApp())이 실행되면MyApp위젯이 화면의 루트가 됨
2) MyApp 위젯 생성
MyApp은StatelessWidget을 상속 받음
➡️ 내부 상태를 직접 바꾸면서 화면을 갱신하는 구조가 아니라, 주어진 값으로 화면을 그리는 정적인 위젯
3) build() 호출
- Flutter는 화면을 그릴 때
build(BuildContext context)를 호출
- 여기서 반환한 위젯 트리가 실제 화면 UI가 됨
print("다시 그려짐")은 build가 다시 호출될 때마다 콘솔에 출력됨
4) 실제 화면 구조
runApp
└─ MyApp
└─ MaterialApp
└─ Scaffold
└─ Column
├─ Padding
│ └─ Row
│ ├─ Text("Women")
│ ├─ Text("Kids")
│ ├─ Text("Shoes")
│ └─ Text("Bag")
├─ Expanded
│ └─ Image.asset("assets/bag.jpeg")
├─ SizedBox(height: 2)
└─ Expanded
└─ Image.asset("assets/cloth.jpeg")3️⃣ 코드 역할 해설
1) import 'package:flutter/material.dart';
- Material Design 스타일 위젯들을 사용하기 위해 가져오는 패키지
MaterialApp,Scaffold,Text,Column,Row,Padding등이 여기에 포함됨
2) void main() { runApp(MyApp()); }
- Dart 프로그램의 시작 함수
runApp()은 전달 받은 위젯을 화면에 붙이는 함수
- Flutter 앱에서는 거의 항상 여기서 루트 위젯을 실행
3) class MyApp extends StatelessWidget
- 화면을 구성하는 사용자 정의 위젯
StatelessWidget은 내부에서 변경되는 상태가 없는 경우 사용
- 버튼 클릭에 따라 값이 바뀌거나 화면이 동적으로 변해야 하면 보통
StatefulWidget을 사용
3) Widget build(BuildContext context)
- Flutter가 화면을 그릴 때 호출하는 핵심 메서드
- 반환 타입이
Widget인 이유는, build가 반드시 하나의 루트 위젯을 반환해야 하기 때문
context는 현재 위젯이 트리에서 어디에 있는지, 상위 위젯 정보가 무엇인지 알 수 있게 해줌
4) return MaterialApp(...)
- Material Design 기반 앱의 가장 바깥 껍데기 역할
- 테마, 라우팅, 기본 앱 구조를 관리
- 이 실습에서는
home속성으로 첫 화면을 바로 지정
5) home: Scaffold(...)
- 실제 한 화면의 기본 틀을 잡아주는 위젯
- 앱바, 바디, 하단 버튼, 드로어 같은 화면 골격을 만들 때 사용
- 이 실습에서는
body만 사용해서 본문 영역만 구성
6) body: Column(...)
- 자식 위젯들을 세로 방향으로 배치
- 위에서 아래로 쌓이는 레이아웃을 만들 때 사용
- 이 실습에서는 메뉴 1줄 + 이미지 2장을 세로로 쌓고 있음
7) children: [ ... ]
Column안에 들어갈 자식 위젯 리스트
- 타입 :
List<Widget>
- Flutter에서
Column,Row,Stack같은 멀티 자식 위젯은 보통children속성에 여러 위젯을 넣음
8) Padding(...)
- 메뉴 줄의 바깥 여백을 주는 역할
- 이 실습에서는
EdgeInsets.all(25.0)으로 상하좌우 25만큼 동일한 여백을 적용
- 메뉴가 화면 가장자리에 너무 붙지 않게 조정
9) child: Row(...)
Padding안쪽에Row를 넣어서 텍스트 메뉴를 가로로 배치
- 메뉴를 가로로 늘어놓고 그 바깥쪽에 여백을 준 구조
10) mainAxisAlignment: MainAxisAlignment.spaceAround
Row의 주축(main axis)은 가로 방향
spaceAround는 각 자식 주변에 일정한 공간을 분배
- 메뉴 항목들이 화면에 고르게 퍼져 보이게 함
11) Text("Women") 등
- 문자열을 화면에 출력하는 가장 기본적인 텍스트 위젯
- 각 텍스트가 카테고리 메뉴 한 칸 역할을 함
12) Expanded(...)
Column안에서 남은 세로 공간을 비율대로 나눠 차지하게 만드는 위젯
- 첫 번째 이미지와 두 번째 이미지 모두
flex: 1이라서 남은 공간을 1:1 비율로 반반씩 사용
13) flex: 1
- 공간 분할 비율을 뜻함
- 예를 들어 위가 1, 아래가 3이면 전체 남은 공간을 1:3으로 나눔
- 이 실습에서는 둘 다 1이므로 동일 비율
14) Image.asset("assets/bag.jpeg")
- 프로젝트 내부
assets폴더의 이미지를 불러와 표시
- 네트워크 이미지가 아니라 번들에 포함된 로컬 이미지를 사용하는 방식
- 이 코드를 쓰려면 보통
pubspec.yaml에 assets 등록이 되어 있어야 함
15) fit: BoxFit.cover
- 이미지가 주어진 영역을 꽉 채우도록 크기를 맞춤
- 비율은 유지하되, 일부가 잘릴 수 있음
- 카드 썸네일이나 배너처럼 빈 공간 없이 꽉 채우고 싶을 때 자주 사용
16) SizedBox(height: 2)
- 위, 아래 이미지 사이에 2픽셀 높이의 간격을 넣음
- 레이아웃 사이 여백이나 고정 크기 공간이 필요할 때 매우 자주 쓰는 위젯
4️⃣ 이 코드에서 배우는 레이아웃 핵심
1) Column은 세로 배치
Column은 자식들을 위에서 아래로 배치
- 현재 화면은 메뉴 줄 1개와 이미지 2개가 세로로 내려가는 구조
2) Row는 가로 배치
Row는 자식들을 왼쪽에서 오른쪽으로 배치
- 카테고리 메뉴를 한 줄로 배치할 때 적합
3) Expanded는 남은 공간 분배
Column안에서 메뉴 줄과 간격을 제외한 나머지 공간을 두 이미지가 나눠 가짐
Expanded가 없으면 이미지는 자기 크기만큼만 차지하거나 overflow가 날 수 있음
4) Padding과 SizedBox의 차이
Padding은 특정 위젯의 바깥 여백을 주는 데 사용
SizedBox는 고정된 크기 자체를 가진 빈 공간을 만들 때 사용
5️⃣ 코드에 나온 Flutter 위젯 정리
1) MaterialApp
- Material Design 기반 앱의 루트 위젯
- 주요 역할
- 앱의 기본 테마 관리
- 첫 화면 지정
- 라우팅과 화면 전환 관리
- 로케일, 디버그 배너, 테마 모드 설정
- 자주 쓰는 옵션
home: 앱이 시작할 때 보여줄 첫 화면theme: 라이트 테마 설정darkTheme: 다크 테마 설정themeMode: 라이트/다크/시스템 설정routes: 이름 기반 라우팅 테이블initialRoute: 시작 라우트 지정debugShowCheckedModeBanner: 디버그 배너 표시 여부navigatorKey: 네비게이터 직접 제어 시 사용builder: 앱 전체를 감싸는 공통 래퍼를 넣고 싶을 때 사용
- 언제 쓰는가
- 안드로이드 느낌의 Material Design 앱을 만들 때 기본적으로 사용
- 대부분 Flutter 입문 예제는
MaterialApp에서 시작
2) CupertinoApp
- iOS 스타일 앱을 만들 때 사용하는 루트 위젯
- 주요 역할
- iOS 느낌의 기본 앱 구조 제공
- Cupertino 테마, 라우팅, 네비게이션 관리
- 자주 쓰는 옵션
home: 첫 화면theme: Cupertino 스타일 테마routes: 이름 기반 화면 이동initialRoute: 시작 라우트navigatorKey: 네비게이터 제어builder: 공통 래퍼 삽입localizationsDelegates: 다국어 처리
- 언제 쓰는가
- iOS 감성의 앱 UI를 강하게 유지하고 싶을 때 사용
CupertinoNavigationBar,CupertinoButton,CupertinoPageScaffold같은 위젯들과 함께 사용- 단, 실제 서비스에서는
MaterialApp안에서 일부만 Cupertino 스타일을 섞는 경우도 많음
※ MaterialApp과 CupertinoApp 비교
MaterialApp은 Google Material Design 중심
CupertinoApp은 Apple iOS UI 중심
- 학습 초기에는
MaterialApp이 자료가 많고 예제가 풍부해서 더 자주 사용
3) Scaffold
- 한 화면의 기본 뼈대를 만드는 위젯
- 주요 역할
- 앱바, 본문, 하단 메뉴, 플로팅 버튼, 드로어 배치
- 화면 단위 레이아웃의 표준 구조 제공
- 자주 쓰는 옵션
appBar: 상단 바body: 화면의 본문floatingActionButton: 우하단 액션 버튼bottomNavigationBar: 하단 네비게이션drawer: 왼쪽 슬라이드 메뉴endDrawer: 오른쪽 슬라이드 메뉴backgroundColor: 배경색resizeToAvoidBottomInset: 키보드 등장 시 body 조정 여부
- 언제 쓰는가
- 하나의 페이지 화면을 만들 때 거의 기본으로 사용
- Material 스타일 앱에서 화면 틀을 잡을 때 표준 선택지
4) Column
- 여러 위젯을 세로 방향으로 배치하는 위젯
- 주요 옵션
children: 배치할 자식 위젯 목록mainAxisAlignment: 세로축 정렬crossAxisAlignment: 가로축 정렬mainAxisSize: 주축 방향으로 얼마나 차지할지textDirection: 텍스트 방향verticalDirection: 자식 배치 순서
- 자주 쓰는
mainAxisAlignment값 start: 위쪽부터 정렬center: 가운데 정렬end: 아래쪽 정렬spaceBetween: 양 끝 고정, 사이 간격 균등spaceAround: 각 자식 주변 여백 균등spaceEvenly: 전체 간격 완전 균등
- 언제 쓰는가
- 화면 요소를 위에서 아래로 쌓고 싶을 때 사용
- 로그인 화면, 프로필 화면, 상세 화면 등에서 매우 자주 사용됨
- 주의할 점
- 자식이 너무 많아 화면을 넘어가면 overflow가 발생할 수 있음
- 스크롤이 필요하면
ListView나SingleChildScrollView를 고려해야 함
5) Row
- 여러 위젯을 가로 방향으로 배치하는 위젯
- 주요 옵션
children: 자식 위젯 목록mainAxisAlignment: 가로축 정렬crossAxisAlignment: 세로축 정렬mainAxisSize: 가로 공간 사용 방식textDirection: 왼쪽에서 오른쪽 / 오른쪽에서 왼쪽 방향
- 언제 쓰는가
- 메뉴, 버튼 묶음, 아이콘 + 텍스트 조합 등을 가로로 정렬할 때 사용한다.
- 현재 실습에서의 의미
Women,Kids,Shoes,Bag를 한 줄 메뉴처럼 보이게 한다.spaceAround를 줘서 각 메뉴 사이 공간을 넉넉하게 만들었다.
6) Padding
- 자식 위젯 바깥쪽에 여백을 주는 위젯
- 주요 옵션
padding: 여백 값 설정 (EdgeInsets사용)child: 감쌀 자식 위젯
- 자주 쓰는
EdgeInsets EdgeInsets.all(값): 모든 방향 동일EdgeInsets.symmetric(horizontal: x, vertical: y): 수평/수직 분리EdgeInsets.only(left: x, top: y, right: z, bottom: w): 방향별 개별 지정
- 언제 쓰는가
- 위젯이 화면 끝에 너무 붙지 않게 하고 싶을 때
- 카드, 버튼, 리스트 항목 등에 여백을 줄 때
7) Text
- 문자열을 출력하는 기본 위젯
- 주요 옵션
style: 글자 크기, 두께, 색상textAlign: 정렬maxLines: 최대 줄 수overflow: 넘칠 때 처리 방식softWrap: 줄바꿈 여부
- 언제 쓰는가
- 거의 모든 화면에서 사용
- 제목, 본문, 라벨, 버튼 텍스트 등 기본 출력 요소
- 예시
Text(
'Women',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
)8) Expanded
Row나Column안에서 남은 공간을 꽉 채우게 만드는 위젯
- 주요 옵션
child: 실제 표시할 자식 위젯flex: 남은 공간을 나누는 비율
- 언제 쓰는가
- 여러 박스가 남은 공간을 비율로 나눠 가져야 할 때
- 이미지, 카드, 버튼 영역을 균등 분할하고 싶을 때
- 현재 실습에서의 의미
- 두 이미지가 세로 영역을 동일 비율로 나눠 가지게 한다.
- 비율 예시
- 위
flex: 1, 아래flex: 1-> 1:1 - 위
flex: 1, 아래flex: 2-> 1:2 - 위
flex: 2, 아래flex: 3-> 2:3
9) Image.asset
- 프로젝트 내부 에셋 이미지를 화면에 띄우는 생성자
- 주요 옵션
fit: 이미지 채우기 방식width,height: 크기 지정alignment: 정렬 위치repeat: 반복 여부color: 색상 오버레이colorBlendMode: 색상 합성 방식
- 자주 쓰는
fit값 BoxFit.cover: 영역을 꽉 채움, 일부 잘릴 수 있음BoxFit.contain: 이미지 전체를 보이게 함, 빈 공간 생길 수 있음BoxFit.fill: 강제로 채움, 비율 깨질 수 있음BoxFit.fitWidth: 너비에 맞춤BoxFit.fitHeight: 높이에 맞춤BoxFit.none: 원본 크기 유지
- 언제 쓰는가
- 앱 로고, 상품 이미지, 배너 이미지 등 로컬 리소스를 보여줄 때 사용
10) SizedBox
- 고정 크기의 빈 공간 또는 고정 크기 박스를 만드는 위젯
- 주요 옵션
width: 가로 크기height: 세로 크기child: 내부 자식 위젯
- 언제 쓰는가
- 위젯 사이 간격을 줄 때
- 버튼, 카드, 이미지에 고정 크기를 줄 때
- 현재 실습에서의 의미
- 두 이미지 사이에 2 높이의 간격을 넣는 용도다.
6️⃣ 이 실습에서 함께 알아야 하는 개념
1) StatelessWidget
- 상태가 없는 위젯을 만들 때 사용
- 외부 값이 바뀌지 않는 한 같은 UI를 반환하는 구조에 적합
- 단순 화면, 소개 페이지, 정적 메뉴 페이지에 자주 사용됨
2) BuildContext
- 위젯이 트리 안에서 어디에 있는지 알려주는 정보다.
- 테마, 네비게이션, 상위 위젯 데이터 접근 시 자주 사용한다.
3) MainAxisAlignment
Row,Column에서 주축 방향 정렬 방식을 정하는 enum이다.
Row에서는 가로축,Column에서는 세로축 기준으로 동작한다.
4) BoxFit
- 이미지가 자신의 영역 안에 어떻게 맞춰질지 정하는 enum이다.
- 상품 썸네일, 배너, 프로필 사진 출력 시 매우 중요하다.
7️⃣ 이 실습 코드를 보고 이해해야 할 것
반드시 이해하면 좋은 포인트
- Flutter 화면은 위젯을 중첩해서 만든다.
- 루트 앱은
MaterialApp또는CupertinoApp으로 시작하는 경우가 많다.
- 한 화면의 틀은
Scaffold가 담당한다.
- 세로 배치는
Column, 가로 배치는Row가 담당한다.
- 남는 공간을 비율로 나누려면
Expanded를 쓴다.
- 간격은
Padding,SizedBox로 조절한다.
- 로컬 이미지는
Image.asset()으로 출력한다.
8️⃣ 실습 코드 개선 아이디어
이 예제를 다음 단계로 확장하면 공부에 도움이 된다.
AppBar를 추가해서 상단 제목 넣기
TextStyle을 적용해서 메뉴 글자 꾸미기
GestureDetector나InkWell을 붙여 메뉴 클릭 가능하게 만들기
ListView로 상품 목록을 스크롤되게 만들기
StatefulWidget으로 선택된 메뉴 상태 바꾸기
BottomNavigationBar를 추가해 실제 스토어 앱 구조처럼 확장하기
Share article