2025. 2. 24. 12:15ㆍ같이 공부합시다 - Flutter/Dart & Flutter 기초부터 실전까지
🚀 주제
✅️ Flutter의 주요 레이아웃 위젯 확인
✅️ 이를 활용 기본적인 화면을 구성
✔ Row(가로 배치)
✔ Column(세로 배치)
✔ Stack(위젯을 겹쳐 배치)
✔ ListView(스크롤 가능한 목록 UI)
📌 소개
| Row | 여러 위젯을 가로로 배치 | 네비게이션 바, 아이콘 버튼 그룹 |
| Column | 여러 위젯을 세로로 배치 | 로그인 화면, 프로필 화면 |
| Stack | 위젯을 겹쳐서 배치 | 프로필 이미지 + 이름, 배경 위에 텍스트 |
| ListView | 스크롤 가능한 리스트 | 채팅 목록, 게시물 리스트 |
1️⃣ Row (가로 배치)
📌 Row는 여러 개의 위젯을 가로로 배치하는 위젯
📌 mainAxisAlignment와 crossAxisAlignment를 사용하여 정렬 가능
🔹 Row 기본 예제
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'test',
home: HomeScreen(),
);
}
}
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('title')),
body: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround, // 가로 정렬
children: [
Container(width: 50, height: 50, color: Colors.red), // 빨간색 박스
Container(width: 50, height: 50, color: Colors.blue), // 파란색 박스
Container(width: 50, height: 50, color: Colors.green), // 초록색 박스
],
),
);
}
}
✔ MainAxisAlignment.spaceAround: 각 아이템 사이에 같은 간격을 둠
✔ 가로 배치 시, 화면을 벗어나지 않도록 주의
[ mainAxisAlignment 옵션에 따른 화면 ]

✅ 축(Axis) 개념
- Main Axis (주축) → Row에서는 가로, Column에서는 세로
- Cross Axis (교차축) → Row에서는 세로, Column에서는 가로
✅ 정렬 방식 비교
| 속성 | Row(가로) | Column(세로) |
| mainAxisAlignment | 좌/우 정렬 | 위/아래 정렬 |
| crossAxisAlignment | 위/아래 정렬 | 좌/우 정렬 |
2️⃣ Column (세로 배치)
📌 Column은 여러 개의 위젯을 세로로 배치하는 위젯
📌 mainAxisAlignment와 crossAxisAlignment로 정렬 가능
🔹 Column 기본 예제
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'test',
home: HomeScreen(),
);
}
}
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('title')),
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Container(width: 50, height: 50, color: Colors.red),
Container(width: 50, height: 50, color: Colors.blue),
Container(width: 50, height: 50, color: Colors.green),
],
),
);
}
}
✔ mainAxisAlignment.center: 세로 방향으로 중앙 정렬
[ mainAxisAlignment 옵션에 따른 화면 ]

3️⃣ Stack (위젯 겹치기)
📌 Stack은 여러 개의 위젯을 겹쳐서 배치하는 위젯
📌 Positioned 위젯을 사용하여 특정 위치에 배치 가능
🔹 Stack 기본 예제
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'test',
home: HomeScreen(),
);
}
}
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('title')),
body: Stack(
children: [
Positioned(
top: 110,
left: 110,
child: Container(width: 150, height: 150, color: Colors.green)),
Positioned(
top: 100,
left: 100,
child: Container(width: 150, height: 150, color: Colors.blue)),
Positioned(
top: 90,
left: 90,
child: Container(width: 150, height: 150, color: Colors.red)),
],
),
);
}
}
✔ 위젯을 겹쳐서 배치할 때 사용
✔ Positioned을 활용하여 특정 위치 지정 가능
[ Stack 테스트 ]

4️⃣ ListView (스크롤 가능한 리스트)
📌 ListView는 화면이 넘칠 경우 스크롤 가능한 리스트를 만드는 위젯
📌 ListView.builder()를 사용하여 동적인 리스트 생성 가능
🔹 ListView 기본 예제
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'test',
home: HomeScreen(),
);
}
}
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('title')),
body: ListView(
children: [
Card(
elevation: 8.0,
child: ListTile(
leading: Icon(Icons.person),
title: Text('tester'),
subtitle: Text('Flutter 개발자'),
),
),
Card(
elevation: 8.0,
child: ListTile(
leading: Icon(Icons.person),
title: Text('tester'),
subtitle: Text('Flutter 개발자'),
),
),
Card(
elevation: 8.0,
child: ListTile(
leading: Icon(Icons.person),
title: Text('tester'),
subtitle: Text('Flutter 개발자'),
),
),
Card(
elevation: 8.0,
child: ListTile(
leading: Icon(Icons.person),
title: Text('tester'),
subtitle: Text('Flutter 개발자'),
),
),
Card(
elevation: 8.0,
child: ListTile(
leading: Icon(Icons.person),
title: Text('tester'),
subtitle: Text('Flutter 개발자'),
),
),
Card(
elevation: 8.0,
child: ListTile(
leading: Icon(Icons.person),
title: Text('tester'),
subtitle: Text('Flutter 개발자'),
),
),
Card(
elevation: 8.0,
child: ListTile(
leading: Icon(Icons.person),
title: Text('tester'),
subtitle: Text('Flutter 개발자'),
),
),
Card(
elevation: 8.0,
child: ListTile(
leading: Icon(Icons.person),
title: Text('tester'),
subtitle: Text('Flutter 개발자'),
),
),
Card(
elevation: 8.0,
child: ListTile(
leading: Icon(Icons.person),
title: Text('tester'),
subtitle: Text('Flutter 개발자'),
),
),
],
),
);
}
}
✔ ListTile을 활용하면 간단한 리스트 아이템을 쉽게 구성 가능
✔ 스크롤이 자동으로 적용됨
[ ListView 테스트 ]

📌 ListView와 Column의 차이점
| 속성 | Column | ListView |
| 스크롤 가능 여부 | ❌ 불가능 | ✅ 가능 |
| 성능 | ❌ 아이템이 많으면 성능 저하 | ✅ 필요할 때만 렌더링 |
| 사용 사례 | 정적인 UI 배치 | 긴 목록 데이터 표시 |
💡 많은 데이터를 표시할 때는 ListView를 사용해야 성능이 좋음!
📌 많은 데이터를 다룰 때는 ListView.builder()를 사용하는 것이 더 효율적. (렌더링 성능 최적화)
ListView.builder(
itemCount: 10, // 10개의 아이템 생성
itemBuilder: (context, index) {
return Card(
elevation: 4.0,
child: ListTile(
leading: Icon(Icons.person),
title: Text("사용자 ${index + 1}"),
subtitle: Text("Flutter 개발자"),
),
);
},
)
5️⃣ Row, Column, Stack, ListView 조합 테스트
🔹 예제
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: const ProfileScreen(),
);
}
}
class ProfileScreen extends StatelessWidget {
const ProfileScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('프로필 화면'),
backgroundColor: Colors.teal,
),
body: Column(
children: [
// 📌 1. Stack을 이용해 프로필 사진과 이름을 겹쳐 배치
Stack(
alignment: Alignment.center,
children: [
Container(
width: double.infinity,
height: 150,
color: Colors.teal.withValues(alpha: 0.3), // 배경색 효과
),
Column(
children: [
ClipOval(
child: Image.network(
'<https://picsum.photos/600/400>',
width: 80,
height: 80,
fit: BoxFit.cover,
),
),
const SizedBox(height: 8),
const Text(
'SteadyBuilder',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
],
),
],
),
// 📌 2. Row를 활용해 버튼 배치
Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
ElevatedButton(
onPressed: () {},
child: const Text('메시지 보내기'),
),
ElevatedButton(
onPressed: () {},
child: const Text('✔팔로우'),
),
],
),
),
// 📌 3. ListView + Expanded를 활용해 스크롤 가능한 목록 UI
Expanded(
child: ListView(
padding: const EdgeInsets.all(10),
children: List.generate(
10,
(index) => Card(
elevation: 4.0,
margin: const EdgeInsets.symmetric(vertical: 5),
child: ListTile(
leading: const Icon(Icons.article),
title: Text('게시물 ${index + 1}'),
subtitle: const Text('이것은 게시물 설명입니다.'),
trailing: const Icon(Icons.arrow_forward_ios, size: 16),
),
),
),
),
),
],
),
);
}
}
[ 조합 테스트 결과 ]

📌 오늘의 실습 과제
✅ [실습 1] Row를 사용하여 아이콘을 가로로 배치하는 UI 만들기
✅ [실습 2] Column을 사용하여 텍스트와 버튼을 세로로 배치하는 UI 만들기
✅ [실습 3] ListView를 사용하여 이름과 직업이 표시되는 리스트 UI
✅ [실습 4] Stack을 활용하여 이미지 위에 텍스트를 배치하는 UI 만들기