✅ Flutter 레이아웃 흐름 총정리
📌 레이아웃 3단계 프로세스
단계 | 설명 |
1단계 | 부모 → 자식에게 제약(BoxConstraints) 을 전달 |
2단계 | 자식은 그 제약 안에서 원하는 크기를 정함 |
3단계 | 부모는 자식의 크기와 위치를 결정함 (Alignment 등 사용 가능) |
📌 크기 결정 우선순위
- 부모의 제약조건 (
BoxConstraints
) maxWidth
,minWidth
,maxHeight
,minHeight
- 자식은 이 제약 안에서만 크기 설정 가능
- 예:
Container(width: 100)
,SizedBox(height: 50)
- 자신이 명시한 크기 (
width
,height
) - 단, 부모의 제약을 벗어나면 무시되거나 잘림
- 내부 콘텐츠의 크기 (
intrinsic size
) - 예:
Text
,Image
,Icon
등의 실제 콘텐츠 크기
- 기본 정렬/축 방향 특성
Row
: 가로는 loose(느슨), 세로는 tight(빡빡)Column
: 가로는 loose, 세로는 tightCenter
,Align
: loose한 제약 제공 (자식이 자기 크기를 갖도록 함)
✅ 부모 제약의 강/약에 따른 자식의 크기 결정
✅ 부모가 강한 제약 (tight)
- 예:
Container(width: 100, height: 100)
- 자식은 별도 크기가 없으면 부모만큼 커짐
- 자식이 크기를 명시해도 부모 제약 안에서만 유효
✅ 부모가 약한 제약 (loose)
- 예:
Column
,Row
,Center
,Padding
- 자식은 자신의 크기대로 자리 잡을 수 있음
- 자식의
width
,height
또는 콘텐츠에 따라 유연하게 결정됨
✅ 자주 헷갈리는 위젯 제약 요약
위젯 | 제약 특징 | 설명 |
Container | 보통 tight | width , height 지정하면 자식은 그만큼 제약받음 |
Center , Align | loose | 자식이 자신의 크기를 가질 수 있도록 느슨한 제약 |
Padding , SizedBox | loose + offset | 자식에게 느슨한 제약 + padding/크기 조절 |
Column | 세로: tight, 가로: loose | 자식의 세로 크기는 제한됨 |
Row | 가로: tight, 세로: loose | 자식의 가로 크기는 제한됨 |
ClipOval , ClipRRect | 부모의 자식일 뿐, 제약을 새로 주진 않음 | 자식의 렌더링만 잘라냄 (제약은 그대로 전달됨) |
✅ 정리 문장 (핵심 요약)
- Flutter 레이아웃은 “제약을 준다 → 자식이 크기 결정 → 부모가 위치/크기 배치”의 3단계로 동작
- 자식은 항상 부모의 제약 안에서만 크기를 정할 수 있음
- 자식에게 크기를 주더라도 부모가 tight한 제약이면 무시되거나 잘림
- loose한 부모(
Center
,Align
,Padding
)가 자식을 자유롭게 키울 수 있게 해줌
1. 부모의 제약 조건은 자식에게 전파된다
바로 밑에 있는 자식에게 자신의 제약조건을 준다


2. 자식은 부모의 제약조건 내에서 크기를 가질 수 있다


3. 자식이 크기가 없으면 부모의 max제약조건을 따라간다
자식이 부모의 min을 따라가면 크기가 없어서 그릴 수 없기 때문
예) minHeight : 0 이면 자식도 0에 따라가서 그려질 수가 없다


4. 부모의 제약조건이 없고 자식이 있는 경우


5. 위 3가지의 제약조건을 따르지 않는 경우
해당 위젯은 다음과 같은 제약조건을 따로 만들어 뒀을 것
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final bool hasChild = true; // 테스트: 자식이 있는지 여부
final double? width = null; // 너비 설정
final double? height = null; // 높이 설정
@override
Widget build(BuildContext context) {
Widget? child = hasChild ? Text('Child') : null;
BoxConstraints constraints;
if (width != null || height != null) {
constraints = BoxConstraints.tightFor(width: width, height: height); // 명시된 크기
} else if (child != null) {
constraints = BoxConstraints(); // 자식이 있으니 최소 제약 → 자식 크기에 맞춰짐
} else {
constraints = BoxConstraints.expand(); // 자식도 없고 크기도 없으면 → 전체화면
}
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Dynamic Constraints')),
body: Center(
child: Container(
constraints: constraints,
color: Colors.blue,
child: Container(
color: Colors.red,
child: child,
),
),
),
),
);
}
}
6. 제약조건 해결방법
1. 제약조건 문제 발생

버튼은 가로 방향으로 무한이다 = 부모의 제약조건을 따르겠다
2. 원인
❗문제: fixedSize: Size(double.infinity, 60)
fixedSize
는 “정확히 이만큼 돼야 해!” 라는 요청이에요.
- 그런데
Size(double.infinity, 60)
는 말이 안 되는 요청이에요. - ❌ 너비를 무한대로 하라는 건 Flutter가 이해할 수 없어요.
- Flutter는 “무한은 안 되니 fallback 사이즈를 써야겠다”고 판단하고,
- 결국 버튼 입장에서는 “부모 제약 무시하고, 내가 가진 자식(텍스트)의 크기만큼만 쓰자”고 결정합니다.
3. 해결
✅ 해결 방법

방법 1:
minimumSize
를 사용 (권장)minimumSize
는 "최소 이만큼은 되어야 한다"는 의미이기 때문에double.infinity
가 허용됩니다.
- 이 경우
Column
에서 받은 가로 제약(maxWidth)를 사용하게 되어 버튼이 가로로 꽉 찹니다.

Share article