(Flutter-기초 강의) 9. Layout Widgets (Column, Row, Container, Stack, etc..)

Flutter에서의 Layout Widget은 앱의 UI를 구성하는 데 있어 핵심적인 역할을 합니다.

이들은 다양한 방식으로 Widget을 배치하고, 조정하여 원하는 디자인과 구조를 만들 수 있게 해줍니다.

주요 Layout Widget에 대하여 간단한 예시 코드와 함께 소개하겠습니다.

아래 예제의 전체 소스는 GitHub Repository 에 있습니다.

Container

소개

여백, 정렬, 크기 등을 설정할 수 있는 범용 Widget입니다.

속성

  • padding: 자식과 컨테이너의 가장자리 사이의 여백.
  • color: 컨테이너의 색상.
  • decoration: 자식 뒤에 그려질 장식.
  • margin: 컨테이너를 둘러싼 여백.
  • width, height: 컨테이너의 크기.
  • alignment: 컨테이너 내에서의 자식의 정렬.

예시 코드

200px x200px 의 배경이 파란 사각형 컨테이너를 생성하고, 안에 상하좌우 padding 20px을 주고 자식 widget으로 Text widget을 추가합니다.

      Container(
        padding: const EdgeInsets.all(20.0),
        color: Colors.blue,
        width: 200,
        height: 200,
        child: const Text(
          'Hello World',
          style: TextStyle(
            color: Colors.white,
            fontSize: 20,
          ),
        ),
      ),

결과

layout container

Row

소개

세로 방향으로 자식 Widget을 정렬합니다.

속성

  • mainAxisAlignment: 주 축(로우의 경우 수평)을 따라 자식들이 배치되는 방식.
  • crossAxisAlignment: 교차 축(로우의 경우 수직)을 따라 자식들이 배치되는 방식.
  • mainAxisSize: 주 축이 차지해야 하는 공간의 양.

예시 코드

3개의 다른 색의 container를 수평 방향으로 나열합니다.

주축(main axis)는 균등한 간격으로 배치되고, 교차 축(cross axis)은 시작 부분에 맞추어 정렬됩니다.

      Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Container(
            color: Colors.red,
            width: 100,
            height: 100,
          ),
          Container(
            color: Colors.green,
            width: 100,
            height: 100,
          ),
          Container(
            color: Colors.blue,
            width: 100,
            height: 100,
          ),
        ],
      ),

결과

layout row

Column

소개

가로 방향으로 자식 Widget을 정렬합니다.

속성

  • mainAxisAlignment: 주 축(컬럼의 경우 수직)을 따라 자식들이 배치되는 방식.
  • crossAxisAlignment: 교차 축(컬럼의 경우 수평)을 따라 자식들이 배치되는 방식.
  • mainAxisSize: 주 축이 차지해야 하는 공간의 양.

예시 코드

3개의 다른 색의 container를 수직 방향으로 나열합니다.

주축(main axis)는 균등한 간격으로 배치되고, 교차 축(cross axis)은 시작 부분에 맞추어 정렬됩니다.

      Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Container(
            color: Colors.red,
            width: 100,
            height: 100,
          ),
          Container(
            color: Colors.green,
            width: 100,
            height: 100,
          ),
          Container(
            color: Colors.blue,
            width: 100,
            height: 100,
          ),
        ],
      ),

결과

layout column

Stack & Positioned

소개

Stack

Widget을 겹쳐서 배치합니다.

Positioned

Stack 내에서 Widget의 위치를 조정합니다.

속성

  • alignment (Stack): 자식들이 서로 대비하여 어떻게 정렬될지.
  • top, right, bottom, left (Positioned): 스택 내에서 자식의 정확한 위치.

예시 코드

하단으로 부터 10px 우측에서 부터 10px 떨어져서 Widget을 위치시켰습니다.

      Stack(
        children: <Widget>[
          Container(
            color: Colors.red,
            width: 200,
            height: 200,
          ),
          const Positioned(
            bottom: 10.0,
            right: 10.0,
            child: Text(
              'On top of image',
              style: TextStyle(fontSize: 20, color: Colors.white),
            ),
          ),
        ],
      ),

결과

layout stackedPositionedWidget

Expanded

소개

주로 Row, Column, 또는 Flex 같은 부모 위젯 내에서 사용됩니다.
자식 위젯을 확장하여 주변 공간을 채우게 하여, 주어진 방향(가로 또는 세로)으로 사용 가능한 공간을 모두 차지하도록 합니다.

속성

  • flex: 사용 가능한 공간 내에서 자식 위젯이 차지하는 비율을 결정합니다. 모든 Expanded 위젯의 flex 값을 합산하여, 각 Expanded 위젯이 차지하는 공간의 비율을 계산합니다.

예시 코드

첫 번째와 두 번째 컨테이너는 각각 100px의 너비를 유지하는 반면, 세 번째 Expanded widget으로 감싸진 컨테이너는 나머지 공간을 모두 채우게 됩니다.

      Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Container(
            color: Colors.red,
            width: 100,
            height: 100,
          ),
          Container(
            color: Colors.green,
            width: 100,
            height: 100,
          ),
          Expanded(
            child: Container(
              color: Colors.blue,
              width: 100,
              height: 100,
            ),
          ),
        ],
      ),

결과

layout Expaned

Flexible

소개

Row, Column, 또는 Flex 같은 부모 위젯 내에서 사용됩니다.

자식 Widget 에게 남은 공간을 어떻게 유연하게 배분합니다.

flex 속성을 사용하여 사용 가능한 공간 내에서 각 자식 Widget이 차지할 공간의 비율을 조정할 수 있으며, fit 속성으로 자식의 크기를 어떻게 조정할지 결정할 수 있습니다.

속성

  • flex: 사용 가능한 공간 내에서 자식 Widget이 차지하는 비율을 결정합니다. 모든 Flexible Widget의 flex 값을 합산하여, 각 Flexible Widget이 차지하는 공간의 비율을 계산합니다.
  • fit: FlexFit을 사용하여 자식 Widget이 남은 공간을 어떻게 채울지 결정합니다. FlexFit.tight는 자식이 할당된 공간을 모두 채우도록 합니다(이는 Expanded와 유사한 행동입니다), 반면에 FlexFit.loose는 자식 Widget이 필요한 만큼의 공간만 차지하도록 허용합니다.

예시 코드

Row의 자식 위젯들로 배치된 Flexible widget들은 주어진 flex값에 해당하는 비율로 표시됩니다.

      Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Flexible(
            flex: 1,
            fit: FlexFit.tight,
            child: Container(
              color: Colors.red,
              height: 100,
            ),
          ),
          Flexible(
            flex: 2,
            fit: FlexFit.loose,
            child: Container(
              color: Colors.green,
              height: 100,
            ),
          ),
          Flexible(
            flex: 4,
            child: Container(
              color: Colors.blue,
              height: 100,
            ),
          ),
        ],
      ),

결과

layout Flexible

Padding

소개

자식 Widget 주변에 여백을 추가합니다.

속성

  • padding: 자식을 안쪽으로 들여쓸 공간의 양.

예시 코드

자식 위젯들을 주어진 값 만큼 띄어서 표시합니다.

      body: Row(
        children: [
          Padding(
            padding: const EdgeInsets.all(50.0),
            child: Container(
              color: Colors.red,
              width: 50,
              height: 50,
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(30.0),
            child: Container(
              color: Colors.green,
              width: 50,
              height: 50,
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(10.0),
            child: Container(
              color: Colors.blue,
              width: 50,
              height: 50,
            ),
          ),
        ],
      ),

결과

layout padding

GridView

소개

격자 형태로 아이템을 배치합니다. 주로 이미지 갤러리, 제품 목록 등에 사용됩니다.

속성

  • gridDelegate: 그리드의 레이아웃을 제어합니다.
  • scrollDirection: 스크롤 뷰가 스크롤되는 축.

예시 코드

4개의 Container들을 1줄에 2개씩 표시합니다.

      body: GridView.count(
        crossAxisCount: 2,
        children: [
          Container(
            color: Colors.red,
          ),
          Container(
            color: Colors.green,
          ),
          Container(
            color: Colors.blue,
          ),
          Container(
            color: Colors.yellow,
          ),
        ],
      ),

결과

layout grid

Wrap

소개

자식들을 수평 또는 수직 방향으로 배치하고, 공간이 부족하면 다음 줄로 넘깁니다.

속성

  • direction: 주 축으로 사용할 방향.
  • alignment: 한 줄 안에서 어떻게 자식들을 주 축에 배치할지.
  • spacing: 각 자식 사이의 공간.
  • runSpacing: 자식들의 각 실행(run) 사이의 공간입니다. 수평 Wrap의 경우, 감싸기가 발생할 때 수직 공간을 제어합니다.

예시 코드

8px씩 사이를 주고 자식 widget들을 끝에 맞추어 배치하고 마지막 줄에 걸치면 자동 줄바꿈하여 다음 자식 Widget을 표시합니다.

      const Wrap(
        spacing: 8.0,
        alignment: WrapAlignment.end,
        children: [
          Chip(
            avatar: CircleAvatar(
              backgroundColor: Colors.orange,
              child: Text('AH', style: TextStyle(fontSize: 10)),
            ),
            label: Text('Hamilton'),
          ),
          Chip(
            avatar: CircleAvatar(
              backgroundColor: Colors.pink,
              child: Text('ML', style: TextStyle(fontSize: 10)),
            ),
            label: Text('Lafayette'),
          ),
          Chip(
            avatar: CircleAvatar(
              backgroundColor: Colors.lightBlue,
              child: Text('HM', style: TextStyle(fontSize: 10)),
            ),
            label: Text('Mulligan'),
          ),
          Chip(
            avatar: CircleAvatar(
              backgroundColor: Colors.green,
              child: Text('JL', style: TextStyle(fontSize: 10)),
            ),
            label: Text('Laurens'),
          ),
        ],
      ),

결과

layout wrap

ListView

소개

스크롤 가능한 세로 목록을 생성합니다.

속성

  • scrollDirection: 리스트가 스크롤되는 축.
  • padding: 자식들을 들여쓸 공간의 양.

예시 코드

자식 위젯들을 세로 방향으로 리스트 형식으로 표시합니다.

      ListView(
        scrollDirection: Axis.vertical,
        padding: const EdgeInsets.all(16),
        children: <Widget>[
          Container(
            color: Colors.red,
            width: 100,
            height: 100,
          ),
          Container(
            color: Colors.green,
            width: 100,
            height: 100,
          ),
          Container(
            color: Colors.blue,
            width: 100,
            height: 100,
          ),
          Container(
            color: Colors.yellow,
            width: 100,
            height: 100,
          ),
          Container(
            color: Colors.orange,
            width: 100,
            height: 100,
          ),
          Container(
            color: Colors.purple,
            width: 100,
            height: 100,
          ),
        ],
      ),

결과

layout ListView

SizedBox

소개

특정 크기의 공간을 만들 때 사용합니다.

주로 Widget 간의 간격을 조절할 때 사용하거나, 자식 Widget들의 크기를 제한할 수 있습니다.

속성

  • width: 박스의 가로 너비
  • height: 박스의 세로 길이

예시 코드

Width: 100px, Height: 100px 고정크기로 제한하는 Box를 생성합니다.

      SizedBox(
        width: 100,
        height: 100,
        child: Container(
          width: 1000,
          height: 1000,
          color: Colors.red,
        ),
      ),

결과

layout SizedBox

SingleChildScrollView

소개

단일 자식을 스크롤 가능하게 만듭니다. 주로 긴 내용을 스크롤하여 볼 수 있게 할 때 사용됩니다.

속성

  • scrollDirection: 스크롤 뷰가 스크롤되는 축.

예시 코드

50개 Container를 자식 Widget으로 갖는 Column을 세로 축으로 스크롤이 가능하게 합니다.

      body: SingleChildScrollView(
        // scroll's direction is vertical (default)
        scrollDirection: Axis.vertical,
        child: Column(
          children: List.generate(
            50,
            (index) => Container(
              height: 50,
              color: index % 2 == 0 ? Colors.yellow : Colors.pink,
              child: Center(
                child: Text('Item $index'),
              ),
            ),
          ),
        ),
      ),

결과

layout SingleChildScroll

결론

위와 같이 다양하게 Widget들을 배치할 수 있는 Layout Widget들이 존재합니다.

각 Widget들만의 다양한 특성과 속성값들을 이용하여 원하는 Layout을 꾸며 볼 수 있습니다.

참고 링크

Flutter Official Document (Layout)

Medium (Layout Widgets)

Leave a Comment