[Flutter] flutter 제약조건

만들면서 배우는 플러터 앱 프로그래밍
최재원's avatar
Jul 30, 2025
[Flutter] flutter 제약조건

✅ Flutter 레이아웃 흐름 총정리

📌 레이아웃 3단계 프로세스

단계
설명
1단계
부모 → 자식에게 제약(BoxConstraints) 을 전달
2단계
자식은 그 제약 안에서 원하는 크기를 정함
3단계
부모는 자식의 크기와 위치를 결정함 (Alignment 등 사용 가능)

📌 크기 결정 우선순위

  1. 부모의 제약조건 (BoxConstraints)
      • maxWidth, minWidth, maxHeight, minHeight
      • 자식은 이 제약 안에서만 크기 설정 가능
      • 예: Container(width: 100), SizedBox(height: 50)
  1. 자신이 명시한 크기 (width, height)
      • 단, 부모의 제약을 벗어나면 무시되거나 잘림
  1. 내부 콘텐츠의 크기 (intrinsic size)
      • 예: Text, Image, Icon 등의 실제 콘텐츠 크기
  1. 기본 정렬/축 방향 특성
      • Row: 가로는 loose(느슨), 세로는 tight(빡빡)
      • Column: 가로는 loose, 세로는 tight
      • Center, 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. 부모의 제약 조건은 자식에게 전파된다

바로 밑에 있는 자식에게 자신의 제약조건을 준다

notion image
notion image

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

notion image
notion image

3. 자식이 크기가 없으면 부모의 max제약조건을 따라간다

자식이 부모의 min을 따라가면 크기가 없어서 그릴 수 없기 때문

예) minHeight : 0 이면 자식도 0에 따라가서 그려질 수가 없다
notion image
notion image

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

notion image
notion image

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. 제약조건 문제 발생

ListView 에서 사용할 땐 문제가 없었다

notion image
notion image

Column 을 사용하니 문제가 생김

notion image
notion image
notion image
버튼은 가로 방향으로 무한이다 = 부모의 제약조건을 따르겠다

2. 원인

❗문제: fixedSize: Size(double.infinity, 60)

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

3. 해결

✅ 해결 방법

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

jjack1