1. 플러터 프로젝트 생성


- 이름 생성할 때 소문자만 가능 (언더스코어 기법)
- 절대 아래는 쓰면 안됨 → 오류 발생 가능성 ⚠️
- 대문자 X
- “-” 안됨

- 코드 작성은 여기서 하는 거임!! (lib → main.dart)

1. runApp 말고 다 지우기
- const도 지금은 지우기

2. MyApp = 위젯
- stl 입력 후 자동 완성으로 코드 생성 → MyApp 추가
- 여기서 MyApp은 위젯임

- 아직 const 안 배워서 지우기

- 생성자도 우선 지워 놓기 (선택적 매개변수 this.key 들고 있는 거, super.key)

3. 이게 위젯 (사진 대신 넣어줌)
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Placeholder(); // 이 리턴 값으로 그림을 그린다
}
}

2. 화면 구조 보기
- 무조건
MaterialAPP
과Scaffold
로 감싸야 한다!!!
1. 화면 구조
- Column 위젯 = 수직, 자식을 여러 개 가질 수 있는 배열을 가진다
- Row 위젯 = 수평, 여러 개를 가질 수 있는 배열을 가진다
- Row는 가로 방향으로 전체를 차지함 (Block과 같음)
- Row의 크기는 전체
- Row는 세로축으로
- Column은 세로 방향으로 차지함 (inline과 같음)
- Column의 크기는 내부의 아이템의 크기로 결정됨
- Column은 가로축으로 inline
✅ Row와 Column의 차이 정리
📦 Row
– 수평 방향 레이아웃 (가로로 나열)
특징 | 설명 |
방향 | 가로 (수평) 방향으로 자식들을 나열함 |
메인 축 | 가로축 (horizontal) |
서브 축 | 세로축 (vertical) |
기본 크기 | 자식들의 너비를 고려하여 부모가 허용하는 전체 가로 공간을 차지함 (block처럼 확장) |
세로 크기 | 자식 위젯 중 가장 큰 높이를 기준으로 함 (세로는 자식에 따라 달라짐) |
Row는 세로축으로 inline | 세로 방향으로는 자식 크기만큼만 공간을 가짐 (inline처럼) |
📦 Column
– 수직 방향 레이아웃 (세로로 나열)
특징 | 설명 |
방향 | 세로 (수직) 방향으로 자식들을 나열함 |
메인 축 | 세로축 (vertical) |
서브 축 | 가로축 (horizontal) |
기본 크기 | 자식들의 높이를 기준으로 필요한 만큼만 높이 차지 (inline처럼 동작) |
가로 크기 | 자식 위젯 중 가장 넓은 폭을 기준으로 함 |
Column은 가로축으로 inline | 가로 방향으로는 자식 크기만큼만 공간을 가짐 (inline처럼) |
🧠 쉽게 외우는 방법
개념 | Row (가로 배치) | Column (세로 배치) |
Block 방향 | 가로 방향을 꽉 채움 (Block처럼) | 세로 방향을 꽉 채움 (Block처럼) |
Inline 방향 | 세로 방향은 자식만큼만 차지 (inline처럼) | 가로 방향은 자식만큼만 차지 (inline처럼) |
Main Axis | Horizontal (가로) | Vertical (세로) |
Cross Axis | Vertical (세로) | Horizontal (가로) |
Flutter Inspector (검사, F12랑 같은 기능, 영역 확인 가능)
Row 선택했을 때
- Row 선택 → Select Widget Mode → 실행된 웹 확인


Column 선택했을 때


2. MaterialApp VS CupertinoApp
- MaterialApp은 안드로이드 디자인
- CupertinoApp은 IOS 디자인
3. Scaffold
- Flutter에서 앱 화면을 만들기 위한 기본 틀
- Scaffold로 틀부터 만들고 그 안에 내용을 넣는 구조
- flutter 앱에서 자주 쓰는 기본 UI 요소들이
Scaffold
안에 있음
- 기본 UI 요소
요소 | 설명 |
appBar | 상단 툴바(앱 제목, 메뉴 아이콘 등) |
body | 실제 화면의 주 내용 |
bottomNavigationBar | 하단 탭바 메뉴 |
floatingActionButton | 오른쪽 하단의 동그란 버튼 (FAB) |
3. 위젯
참고 자료


Childern: [] 설명

- Children: [] : 배열 넣을 수 있음
- 여러 위젯을 담는 위젯(Container 역할)
![Childern: [] 설명](https://image.inblog.dev?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fattachment%3A86e70c92-480c-4b59-bf7d-82420acfa08b%3Aimage.png%3Ftable%3Dblock%26id%3D1faadaf3-6517-80ee-bd40-e06ab6467ebb%26cache%3Dv2&w=1920&q=75)
Text 위젯
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 이 리턴 값으로 그림을 그린다
return MaterialApp(
// 안드로이드 디자인, CupertinoApp은 IOS 디자인
// home: 은 앱 실행 시 가장 먼저 보여줄 위젯을 설정하는 프로퍼티
home: Scaffold(
body: Column(
children: [
Row(
children: [
Text("Women"),
Text("Women"),
Text("Women"),
Text("Women"),
],
),
],
),
),
);
}
}

Spacer 위젯
- html 에서 flex와 비슷한 기능
- 빈 공간이 생김 (남는 공간 다 차지 함, Expanded랑 기능은 같지만 특징은 다름)
- Expanded와 다르게 자식을 가질 수 없음

import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 이 리턴 값으로 그림을 그린다
return MaterialApp(
// 안드로이드 디자인, CupertinoApp은 IOS 디자인
// home: 은 앱 실행 시 가장 먼저 보여줄 위젯을 설정하는 프로퍼티
home: Scaffold(
body: Column(
children: [
Row(
children: [
Spacer(),
Text("Women"),
Spacer(),
Text("Women"),
Spacer(),
Text("Women"),
Spacer(),
Text("Women"),
Spacer(),
],
),
],
),
),
);
}
}

Row → mainAxisAlignment: , 위젯
- Row 기준에서 사용
- flex의 justify: content와 같음


Padding 위젯
Padding 생성하고 싶으면?
Row에 커서 올리고 Alt + Enter

import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 이 리턴 값으로 그림을 그린다
return MaterialApp(
// 안드로이드 디자인, CupertinoApp은 IOS 디자인
// home: 은 앱 실행 시 가장 먼저 보여줄 위젯을 설정하는 프로퍼티
home: Scaffold(
body: Column(
children: [
Padding(
padding: EdgeInsets.all(16.0),
child: Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
Text("Women"),
Text("Women"),
Text("Women"),
Text("Women"),
],
),
),
],
),
),
);
}
}

Padding 삭제 하고 싶으면?
- Padding에 커서 올려놓고 Alt + Enter

import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 이 리턴 값으로 그림을 그린다
return MaterialApp(
// 안드로이드 디자인, CupertinoApp은 IOS 디자인
// home: 은 앱 실행 시 가장 먼저 보여줄 위젯을 설정하는 프로퍼티
home: Scaffold(
body: Column(
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text("Women"),
Text("Women"),
Text("Women"),
Text("Women"),
],
),
],
),
),
);
}
}
SafeArea 위젯
먼저 알아두면 좋은점 (인셋 영역)
- 모바일에는 인셋 영역이 있다
- 엣지 인셋 영역이라고도 하는데, 그 영역은 그림을 못 그리는 구역을 말한다
- 예) 키보드 올라오는 부분, WIFI or 데이터, 배터리, 날씨 등 표시되는 상단 부분

- SafeArea
- 인셋 영역을 해치지 않기 위해 사용한다
Column에서 alt + enter 입력 후 Wrap with widget 선택
→ SafeArea가 따로 나오지 않아서 Wrap with widget을 선택하는 거임!
→ 그 다음 이름만 SafeArea로 바꾸면 됨!!
→ 그러고 나서 다시 Row 를 Padding 으로 감싸기!!


Padding 까지 한 코드
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 이 리턴 값으로 그림을 그린다
return MaterialApp(
// 안드로이드 디자인, CupertinoApp은 IOS 디자인
// home: 은 앱 실행 시 가장 먼저 보여줄 위젯을 설정하는 프로퍼티
home: Scaffold(
body: SafeArea(
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(
25.0,
),
child: Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
Text("Women"),
Text("Women"),
Text("Women"),
Text("Women"),
],
),
),
],
),
),
),
);
}
}

Expanded 위젯
- Expanded를 하면 내부에 있는 자식까지 같이 늘어난다
- 남는 공간을 모두 차지한다 (Spacer 위젯이랑 차이 있음)

Expanded 사용한 코드
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 이 리턴 값으로 그림을 그린다
return MaterialApp(
// 안드로이드 디자인, CupertinoApp은 IOS 디자인
// home: 은 앱 실행 시 가장 먼저 보여줄 위젯을 설정하는 프로퍼티
home: Scaffold(
body: SafeArea(
child: Column(
children: [
Padding(
padding: EdgeInsets.all(25),
child: Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
Text("Women"),
Text("Kids"),
Text("Shoes"),
Text("Bag"),
],
),
),
Expanded(
child: Placeholder(),
flex: 1,
),
Expanded(
child: Placeholder(),
flex: 1,
),
],
),
),
),
);
}
}

SizeBox 사용 (= margin)
코드
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 이 리턴 값으로 그림을 그린다
return MaterialApp(
// 안드로이드 디자인, CupertinoApp은 IOS 디자인
// home: 은 앱 실행 시 가장 먼저 보여줄 위젯을 설정하는 프로퍼티
home: Scaffold(
body: SafeArea(
child: Column(
children: [
Padding(
padding: EdgeInsets.all(25),
child: Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
Text("Women"),
Text("Kids"),
Text("Shoes"),
Text("Bag"),
],
),
),
Expanded(
child: Placeholder(),
flex: 1,
),
SizedBox(height: 10),
Expanded(
child: Placeholder(),
flex: 1,
),
],
),
),
),
);
}
}


Image 위젯
추가 설명
- 실행 세모 버튼을 누르는 거는 -> 전부 다 집어 넣는거
- 저장을 하는 건 그 해당 부분만 다시 넣어지는 거
yaml 설명
- yaml : 중간 언어, json 보다 가벼움 (중괄호가 없다), 경량 언어 (표준은 Json)
- 중간 언어는 통신할 때 쓰임
- 확장자 이름 (.yaml, .yml)
- 배열만 띄워 쓰기만 잘해도 오류가 없음
yaml (.yaml, .yml)
class User {
String username="ssar";
String password="1234";
}
<user>
<username>ssar</username>
<password>1234</password>
</user>
{
"username":"ssar",
"password":"1234"
}
// yaml 규칙
user:
username: ssar // 'username' 앞에는 무조건 두칸 띄우기, ':' 다음엔 무조건 한 칸 띄우기
password: 1234
addr:
first: 부산 // 4칸 띄우기
mid: 수영구
hobby:
- 농구 // 배열 하고 싶을 때는 4칸 띄우고 '-' 쓰기
- 축구
사진 넣기

이미지 경로 잡기


flutter:
uses-material-design: true
assets:
- assets/bag.jpeg
- assets/cloth.jpeg
flutter:
uses-material-design: true
assets:
- assets/
전체 코드
name: flutter_recipe
description: "A new Flutter project."
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.0.0+1
environment:
sdk: ^3.7.2
# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.8
dev_dependencies:
flutter_test:
sdk: flutter
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^5.0.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter packages.
flutter:
uses-material-design: true
assets:
- assets/
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/to/resolution-aware-images
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/to/asset-from-package
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/to/font-from-package
Image.asset
- 로컬 이미지 사용 (
assets/xxx
경로의 이미지 파일)
fit: BoxFit.cover
: 이미지를 공간에 꽉 채우되, 비율 유지하며 잘라냄
SizedBox(height: 2)
- 두 이미지 사이에 2픽셀 간격을 만들어줌
Expanded
- Column/Row 등 Flex 계열 위젯 안에서 사용됨
- 남아 있는 공간을 비율(flex)에 따라 나누어 차지함
- 여기서는 두 개의
Expanded
가flex: 1
씩 설정되어 있음 → 공간을 1:1로 나눔
- 즉,
bag.jpeg
와cloth.jpeg
는 세로로 화면을 반씩 나눠서 보여줌
Expanded(
child: Image.asset(
"assets/bag.jpeg",
fit: BoxFit.cover,
), // 이름있는 생성자, 나중에 네트워크로 넣으려면 Image.netWork 해야함
flex: 1,
),
SizedBox(height: 2),
Expanded(
child: Image.asset(
"assets/cloth.jpeg",
fit: BoxFit.cover,
),
flex: 1,
),

요소 | 설명 |
Expanded | 공간을 flex 비율로 나누기 (반응형 레이아웃 핵심) |
Image.asset | 로컬 이미지 출력 |
BoxFit.cover | 이미지 비율 유지하면서 공간에 꽉 채움 (잘림 가능) |
SizedBox | 위젯 사이 간격 조절용 |
⚠️ 주의

네트워크 이미지로 바꾸고 싶으면?
- 이런 식으로 사용하면 됨
Image.network("https://example.com/image.jpg")
4. 완성
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 이 리턴 값으로 그림을 그린다
return MaterialApp(
// 안드로이드 디자인, CupertinoApp은 IOS 디자인
// home: 은 앱 실행 시 가장 먼저 보여줄 위젯을 설정하는 프로퍼티
home: Scaffold(
body: SafeArea(
child: Column(
children: [
Padding(
padding: EdgeInsets.all(25),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("Women", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
Text("Kids", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
Text("Shoes", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
Text("Bag", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
],
),
),
Expanded(
child: Image.asset(
"assets/bag.jpeg",
fit: BoxFit.cover,
), // 이름있는 생성자, 나중에 네트워크로 넣으려면 Image.netWork 해야함
flex: 1,
),
SizedBox(height: 2),
Expanded(
child: Image.asset(
"assets/cloth.jpeg",
fit: BoxFit.cover,
),
flex: 1,
),
],
),
),
),
);
}
}

다시 만들어보기
Share article