왜 이 내용을 정리하나
Flutter에서 화면을 만들 때 위젯을 세로나 가로로 나란히 놓는 일은 거의 모든 화면에서 반복된다. 프로필 카드에서 이미지 옆에 이름과 설명을 두는 경우, 하단 버튼 두 개를 가로로 나누는 경우, 목록 항목 안에서 아이콘과 텍스트를 한 줄에 맞추는 경우가 모두 여기에 해당한다. 이때 쓰는 기본 위젯이 Column과 Row다. 둘의 동작 방식과 정렬 속성을 정확히 알아 두지 않으면 화면이 깨지거나 오버플로우 경고가 계속 나오기 쉽다. 이 노트에서는 Column과 Row의 기본 개념, 정렬 방식, 자주 부딪히는 문제를 정리해 본다.
개념 설명
Column은 자식 위젯을 위에서 아래로 세로 방향으로 배치한다. Row는 자식 위젯을 왼쪽에서 오른쪽으로 가로 방향으로 배치한다. 두 위젯 모두 children 속성에 List<Widget>을 받는다. 방향이 다를 뿐 구조는 같다.
정렬에는 두 가지 축이 있다. 주축(main axis)은 배치가 진행되는 방향이고, 교차축(cross axis)은 그 수직 방향이다. Column에서는 주축이 세로, 교차축이 가로다. Row에서는 반대다. 이 구분을 헷갈리면 mainAxisAlignment와 crossAxisAlignment를 잘못 고르게 된다.
mainAxisAlignment는 주축을 따라 자식을 어떻게 분포시킬지 정한다. start, end, center, spaceBetween, spaceAround, spaceEvenly 값이 있다. crossAxisAlignment는 교차축에서 정렬을 정한다. start, end, center, stretch, baseline 값이 있다. mainAxisSize는 주축 방향으로 위젯이 차지할 크기를 정하는데, 기본값인 max는 가능한 최대 크기를 쓰고 min은 자식들이 차지하는 만큼만 쓴다.
Column과 Row는 자식의 크기를 제약 조건 안에서 정한다. 자식이 공간을 얼마나 쓸지 고정하고 싶으면 SizedBox나 Container로 감싸고, 남은 공간을 나누어 쓰게 하려면 Expanded나 Flexible을 쓴다. Expanded는 flex 비율만큼 남은 공간을 받는다.
코드 예제
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(home: LayoutDemo()));
}
class LayoutDemo extends StatelessWidget {
const LayoutDemo({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Column과 Row')),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('세로 배치 영역'),
const SizedBox(height: 12),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
width: 80,
height: 40,
color: Colors.blue,
alignment: Alignment.center,
child: const Text('왼쪽'),
),
Container(
width: 80,
height: 40,
color: Colors.green,
alignment: Alignment.center,
child: const Text('오른쪽'),
),
],
),
const SizedBox(height: 12),
Expanded(
child: Row(
children: [
Expanded(
flex: 1,
child: Container(color: Colors.orange),
),
Expanded(
flex: 2,
child: Container(color: Colors.purple),
),
],
),
),
],
),
),
);
}
}
이 코드는 바깥쪽 Column 안에 텍스트, 가로 Row, 그리고 남은 세로 공간을 채우는 Expanded Row를 차례로 배치한다. 바깥 Column의 crossAxisAlignment를 start로 두었으므로 텍스트가 왼쪽에 붙는다. 안쪽 Row의 mainAxisAlignment를 spaceBetween으로 두었기 때문에 두 Container가 양 끝으로 벌어진다. 마지막 Row 안에서는 두 Expanded가 1대 2 비율로 가로 공간을 나눠 가진다. 실행하면 파란색과 초록색 박스가 상단에 나란히 놓이고, 하단 영역에는 주황색과 보라색 블록이 1대 2 폭으로 채워진다.
헷갈리는 점
가장 흔한 실수는 Column 안에 세로로 긴 목록을 넣고 오버플로우 경고를 받는 경우다. Column은 스크롤을 지원하지 않으므로 자식의 전체 높이가 화면을 넘으면 노란색과 검은색 줄무늬 경고가 나타난다. 이때는 Column을 SingleChildScrollView로 감싸거나, 목록이라면 ListView를 쓰는 편이 맞다.
Row 안에 Text를 넣었을 때 글자가 잘리거나 오버플로우가 나는 경우도 많다. Row는 자식에게 무한한 가로 폭을 줄 수 있으므로, 긴 텍스트는 Expanded로 감싸야 남은 공간 안에서 줄바꿈이나 말줄임이 적용된다.
Column 안에서 Expanded를 쓰면 주축인 세로 방향의 남은 공간을 나누게 된다. 반대로 Row 안의 Expanded는 가로 공간을 나눈다. 같은 Expanded라도 어느 축의 부모 안에 있는지에 따라 결과가 달라진다. Expanded를 Column 바로 아래 두지 않고 Row에 넣은 상태로 Column 안에 배치하면 높이 제약이 없어 오류가 날 수 있다는 점도 기억해 두면 좋다.
mainAxisSize.min을 쓰면 Row가 자식만큼만 폭을 차지하므로 버튼 그룹처럼 내용만큼 줄어들어야 하는 경우에 유용하다. 기본값인 max 상태에서는 Row가 부모의 전체 폭을 차지하기 때문에 배경색을 칠하면 의도보다 넓게 보인다.
정리
Column은 세로, Row는 가로로 자식을 배치하며, 정렬은 주축과 교차축 두 축으로 나뉜다. mainAxisAlignment와 crossAxisAlignment의 방향을 구분해서 쓰고, 남은 공간을 나눌 때는 Expanded와 flex를 활용한다. 오버플로우가 나면 스크롤 위젯으로 감싸거나 Expanded를 적절한 위치에 두는 것이 해결의 시작이다. 이 노트에서는 Column과 Row의 기본 구조, 정렬 규칙, 자주 나오는 오류를 정리해 본다.
#Flutter #Column #Row #레이아웃 #위젯
'Flutter' 카테고리의 다른 글
| Dart 명명된 매개변수에서 required와 기본값을 함께 쓸 때의 동작 확인 (0) | 2026.10.24 |
|---|---|
| Dart 레코드를 함수 반환값으로 쓰고 구조 분해로 받아 확인하는 방법 (0) | 2026.10.24 |
| Flutter에서 StatelessWidget과 StatefulWidget을 나누는 기준 (0) | 2026.10.23 |
| Flutter 시작하기 - SDK 다운로드 및 환경 설정 가이드 (1) | 2025.09.03 |
| Riverpod 3.0 정리 – 주요 변경사항과 사용법 (0) | 2025.07.20 |