레이아웃: 위젯으로 화면을 배열하기
레이아웃: 위젯으로 화면을 배열하기
플러터에서 화면을 배치한다는 건 곧 위젯을 조합한다는 뜻이에요. '플러터에선 모든 것이 위젯'이라는 말 그대로, 화면에 보이는 이미지·아이콘·텍스트는 물론, 보이지 않는 행·열·그리드 같은 배치 모델조차 위젯이에요. 그래서 레이아웃을 만들 때는 위젯을 조합해 더 복잡한 위젯을 만들어 가는 방식으로 접근해요.
위젯 하나를 화면에 올리는 법
레이아웃을 짓는 가장 기본 단위는 위젯 하나를 화면에 올리는 일이에요. 이 과정은 몇 단계로 나뉘는데, 순서대로 보면 이래요.
1. 배치 위젯 하나를 고른다. 보이는 위젯을 어떻게 정렬·제약할지는 배치 위젯이 정해요. 예를 들어 Center는 자식을 가로·세로 가운데에 두는 배치 위젯이에요.
Center(
// 여기에 가운데로 보낼 내용이 들어가요.
)
2. 보이는 위젯을 고른다. 화면에 실제로 보일 요소를 담는 위젯이에요. Text(텍스트), Image(이미지), Icon(아이콘) 같은 것들이죠.
Text('Hello World')
3. 둘을 합친다. 배치 위젯들은 자식을 받는 방식이 두 가지로 나뉘어요. 단일 자식을 받으면 child, 위젯 목록을 받으면 children 속성을 써요. Center, Container는 child를, Row, Column, ListView, Stack은 children을 써요. 이제 Text를 Center 안에 넣으면 되죠.
const Center(
child: Text('Hello World'),
),
4. 앱이 되어 화면에 표시한다. 플러터 앱도 결국 하나의 위젯이고, 대부분 위젯은 build() 메서드를 가져요. build()에서 위젯을 만들어 반환하면 화면에 그려져요. 일반 앱이라면 Container를 쓰고, Material 앱이라면 Scaffold를 쓰는 게 편해요. Scaffold는 기본 배너·배경색을 제공하고 서랍(drawer), 스낵바, 바텀 시트를 추가하는 API도 갖고 있어요.
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
const String appTitle = 'Flutter layout demo';
return MaterialApp(
title: appTitle,
home: Scaffold(
appBar: AppBar(title: const Text(appTitle)),
body: const Center(
child: Text('Hello World'),
),
),
);
}
}
Cupertino(iOS 스타일) 앱이라면 CupertinoApp와 CupertinoPageScaffold를 써요. Material과 달리 기본 배너·배경색이 없으니 직접 정해야 해요. 기본 색은 CupertinoThemeData를 theme에 넘겨 정하고, iOS 스타일 네비게이션 바는 CupertinoNavigationBar를 위젯에 추가하며, 본문은 Center나 Column 같은 위젯으로 채워요.
Row와 Column: 가로·세로 배치의 기본
가장 흔한 레이아웃 패턴은 위젯을 가로나 세로로 늘어놓는 거예요. 가로는 Row, 세로는 Column 위젯이 담당해요. 둘 다 자식 목록을 받고, 각 자식은 다시 Row나 Column이 될 수 있어서 서로 중첩해서 쓸 수 있어요.
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Image.asset('images/pic1.jpg'),
Image.asset('images/pic2.jpg'),
Image.asset('images/pic3.jpg'),
],
);
자식 정렬은 mainAxisAlignment와 crossAxisAlignment 속성으로 제어해요. Row의 주 축(main axis)은 가로, 교차 축(cross axis)은 세로예요. 반대로 Column은 주 축이 세로, 교차 축이 가로가 돼요. MainAxisAlignment와 CrossAxisAlignment 열거형에는 정렬을 위한 여러 상수가 정의돼 있어요. 예를 들어 위 코드처럼 spaceEvenly를 쓰면 이미지들 사이와 양 끝에 남는 공간을 똑같이 나눠요. Column도 같은 방식으로 동작해요.
레이아웃이 화면보다 너무 커지면 그 가장자리에 노란색·검은색 줄무늬가 나타나요. 이건 '이쪽이 넘쳤다'고 알려 주는 디버그 표시라, 레이아웃이 예상과 다르게 나온다면 이 줄무늬가 어디 있는지부터 확인해 보세요.
정리: Container, ListTile, 제약
Container는 자식 위젯을 꾸밀 수 있게 해 주는 위젯이에요. 패딩, 마진, 테두리, 배경색 같은 걸 더하고 싶을 때 Container로 자식을 감싸요.
ListTile은 Material 라이브러리가 제공하는 특화된 행 위젯이에요. 텍스트 최대 3줄과 선택적인 앞·뒤 아이콘을 가진 행을 쉽게 만들 수 있어서, Row보다 설정 폭은 좁지만 쓰기는 훨씬 편해요. 주로 Card나 ListView 안에서 많이 써요.
진짜로 플러터 레이아웃을 잘 이해하려면 위치와 크기가 어떻게 정해지는지도 알아야 해요. 플러터의 핵심 규칙은 "제약은 아래로 흐르고, 크기는 위로 흐르며, 부모가 위치를 정한다" 정도로 요약돼요.
더 알아보기
- 배치 위젯 카탈로그: Layout widgets
- 위젯 카탈로그: Widget catalog
- 레이아웃 튜토리얼: Layout tutorial
- 제약 이해하기: Understanding constraints