Flutter Row와 Column 차이: 축·정렬·overflow 해결

핵심 요약
Row는 가로, Column은 세로로 자식을 배치하며 mainAxis와 crossAxis는 위젯 이름이 아니라 현재 배치 방향을 기준으로 해석합니다.

검수 범위
정렬 축, Expanded 사용, 작은 화면에서의 overflow 해결을 공식 위젯 API와 대조했습니다.

Flutter Row Column 차이

Flutter에서 화면을 만들다 보면 가장 자주 만나는 위젯이 Row와 Column입니다. 둘 다 여러 위젯을 한 줄로 정렬할 때 쓰지만, Row는 가로 방향, Column은 세로 방향이라는 차이가 있습니다. 두 위젯 모두 children 목록을 받아서 여러 자식을 배치하고, 정렬 방식도 비슷한 속성으로 맞춥니다.

기본 개념 정리

Row는 위젯들을 왼쪽에서 오른쪽으로 놓습니다.
예를 들어 아이콘 옆에 텍스트를 붙이거나, 버튼 2개를 한 줄에 나란히 보여줄 때 Row를 씁니다. Flutter 공식 API도 Row를 가로 배열로 자식 위젯을 보여주는 위젯으로 설명합니다.

Column은 위젯들을 위에서 아래로 놓습니다.
제목 아래 설명문을 넣거나, 로그인 화면에서 입력창과 버튼을 위아래로 쌓을 때 Column을 씁니다. Flutter 공식 API도 Column을 세로 배열로 자식 위젯을 보여주는 위젯으로 설명합니다.

한 줄 요약 비교

  • Row: 가로로 나란히 배치
  • Column: 세로로 차례대로 배치

이 둘은 방향만 다를 뿐, 사용하는 방식은 꽤 비슷합니다. 그래서 하나를 이해하면 다른 하나도 금방 익힐 수 있습니다. Flutter 레이아웃 문서도 Row와 Column을 가장 많이 쓰는 배치 위젯으로 다루고 있습니다.

화면 배치 예시

Row 사용 예시

Row( children: [ Icon(Icons.star), Text('인기 글'), ElevatedButton( onPressed: () {}, child: Text('확인'), ), ], )

위 코드는 아이콘, 텍스트, 버튼이 한 줄에 가로로 보입니다.

Column 사용 예시

Column( children: [ Text('로그인'), TextField(), TextField(), ElevatedButton( onPressed: () {}, child: Text('로그인하기'), ), ], )

위 코드는 제목, 입력창, 입력창, 버튼이 위에서 아래로 보입니다.

실제 화면에서 생각하면 더 쉽다

가로 메뉴바, 아이콘 묶음, 버튼 묶음은 Row가 잘 맞습니다.
회원가입 화면, 게시글 상세 화면, 설정 화면처럼 내용이 위아래로 이어질 때는 Column이 잘 맞습니다.

즉, 옆으로 놓고 싶으면 Row, 아래로 쌓고 싶으면 Column이라고 생각하면 됩니다.

정렬 속성 이해

Row와 Column은 방향만 다르고, 정렬할 때 쓰는 핵심 속성은 같습니다. 가장 먼저 알아둘 것은 mainAxisAlignmentcrossAxisAlignment입니다. Flutter 레이아웃 문서는 Row와 Column 모두 자식 위젯을 가로와 세로 기준으로 정렬할 수 있다고 설명합니다.

mainAxisAlignment 뜻

mainAxisAlignment현재 위젯이 놓이는 기본 방향 기준 정렬입니다.

  • Row에서 main axis는 가로
  • Column에서 main axis는 세로

즉 Row에서는 왼쪽, 가운데, 오른쪽처럼 가로 기준으로 움직이고, Column에서는 위, 가운데, 아래처럼 세로 기준으로 움직입니다.

예를 들어:

Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text('A'), Text('B'), Text('C'), ], )

이 코드는 A, B, C를 가로줄 가운데로 모읍니다.

crossAxisAlignment 뜻

crossAxisAlignment기본 방향과 반대쪽 기준 정렬입니다.

  • Row에서는 세로 기준 정렬
  • Column에서는 가로 기준 정렬

예를 들어 Row에서 crossAxisAlignment: CrossAxisAlignment.end를 주면, 자식들이 아래쪽 기준으로 맞춰질 수 있습니다. Column에서는 왼쪽 정렬, 가운데 정렬, 오른쪽 정렬 느낌으로 이해하면 쉽습니다. 관련 제약 조건 문서도 Row와 Column의 반대 방향 크기 제약이 중요하다고 설명합니다.

예제로 같이 보기

Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('제목'), Text('설명'), Text('버튼'), ], )

이 경우:

  • mainAxisAlignment.center → 세로 가운데로 모임
  • crossAxisAlignment.start → 가로는 왼쪽부터 시작

처음엔 이름이 낯설지만,
main은 현재 방향, cross는 반대 방향이라고 기억하면 금방 익숙해집니다.

Expanded 함께 이해하기

Row와 Column을 쓰다 보면 Expanded를 자주 같이 씁니다. Flutter 공식 API는 Expanded를 Row, Column, Flex 안에서 남는 공간을 채우도록 확장하는 위젯이라고 설명합니다. 특히 Row에서는 가로 방향, Column에서는 세로 방향의 남는 공간을 채우는 데 사용됩니다.

Row에서 Expanded

Row( children: [ Icon(Icons.search), Expanded( child: TextField(), ), Icon(Icons.close), ], )

이 코드는 가운데 TextField가 남는 가로 공간을 넓게 차지합니다.

Column에서 Expanded

Column( children: [ Text('상단 영역'), Expanded( child: Container( color: Colors.blue, ), ), Text('하단 영역'), ], )

이 코드는 가운데 파란 박스가 남는 세로 공간을 채웁니다.

초보자 입장에서는 이렇게 기억하면 쉽습니다.

  • Row + Expanded = 가로 남는 자리 채우기
  • Column + Expanded = 세로 남는 자리 채우기

자주 헷갈리는 부분

Row에서 글자가 넘치는 경우

Row는 자식들을 한 줄에 가로로 놓기 때문에, 내용이 너무 길면 화면을 넘길 수 있습니다. Flutter Row 문서도 Row는 스크롤하지 않으며, 자식이 공간보다 많으면 문제가 될 수 있다고 안내합니다. 이런 경우에는 Expanded로 남는 공간을 나누거나, 필요하면 ListView 같은 스크롤 위젯을 써야 합니다.

예를 들어 긴 텍스트가 있을 때:

Row( children: [ Icon(Icons.info), Expanded( child: Text( '이 문장은 길어질 수 있어서 Expanded로 감싸는 편이 안전합니다.', ), ), ], )

텍스트를 그냥 넣으면 넘칠 수 있지만, Expanded로 감싸면 사용할 수 있는 가로 공간 안에서 맞춰집니다.

Column에서 아래쪽이 넘치는 경우

Column도 스크롤하지 않습니다. 그래서 자식이 너무 많아 화면 높이를 넘어가면 아래쪽 overflow가 날 수 있습니다. Flutter Column 문서도 Column은 스크롤하지 않으며, 필요한 경우 ListView를 고려하라고 설명합니다.

예를 들어 입력창이 아주 많은 화면이라면:

SingleChildScrollView( child: Column( children: [ TextField(), TextField(), TextField(), TextField(), TextField(), TextField(), ], ), )

이런 식으로 감싸야 작은 화면에서도 안전합니다.

Column 안에 또 Column 넣을 때 주의할 점

Flutter의 제약 조건 문서에 따르면, Flex 계열 위젯인 Row와 Column은 사용 위치에 따라 크기 제한 문제를 만날 수 있고, 특히 스크롤 영역이나 또 다른 Flex 안에서 Expanded를 섞을 때 예외가 발생할 수 있습니다. 초보자가 많이 보는 오류 중 하나가 바로 이 부분입니다.

처음에는 이렇게만 기억해도 충분합니다.

  • Row, Column 안에서 Expanded는 아주 자주 씀
  • 그런데 스크롤 위젯 안이나 크기 제한이 애매한 곳에서는 오류가 날 수 있음
  • 에러가 나면 부모 위젯이 어느 정도 크기를 주는지 먼저 확인해야 함

언제 Row를 쓰고 언제 Column을 쓸까

Row가 잘 맞는 경우

  • 아이콘 + 텍스트를 한 줄에 보여줄 때
  • 버튼 2개 이상을 나란히 놓을 때
  • 프로필 사진 옆에 이름과 소개를 붙일 때
  • 상단 메뉴나 태그 목록을 가로로 놓을 때

Column이 잘 맞는 경우

  • 제목, 설명, 버튼을 위아래로 쌓을 때
  • 로그인, 회원가입, 설정 화면을 만들 때
  • 카드 안에 여러 정보를 세로로 넣을 때
  • 게시글 상세처럼 내용이 아래로 이어질 때

실무에서는 둘 중 하나만 단독으로 쓰는 경우보다, Column 안에 Row, Row 안에 Column처럼 섞어서 쓰는 경우가 훨씬 많습니다. Flutter 레이아웃 문서도 Row와 Column은 서로 중첩해서 쓸 수 있다고 설명합니다.

같이 쓰면 좋은 위젯

SizedBox

간격 줄 때 가장 편합니다.

Row( children: [ Icon(Icons.star), SizedBox(width: 8), Text('즐겨찾기'), ], )

Row에서는 width, Column에서는 height를 많이 씁니다.

Spacer

남는 공간을 띄우고 싶을 때 좋습니다.

Row( children: [ Text('왼쪽'), Spacer(), Text('오른쪽'), ], )

Center

전체를 가운데에 놓고 싶을 때 간단합니다.

Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.login), Text('로그인'), ], ), )

실전 화면 예시

로그인 화면 생각하기

로그인 화면을 만든다고 가정해보겠습니다.

  • 페이지 전체는 위에서 아래로 쌓이니 Column
  • 이메일 입력창과 비밀번호 입력창도 세로로 놓이니 Column
  • 비밀번호 입력창 오른쪽에 눈 아이콘을 붙이면 그 줄은 Row
  • 버튼은 한 개면 굳이 Row 없이 단독 사용 가능

즉 실제 앱 화면은 보통 이렇게 됩니다.

Column( children: [ Text('로그인'), SizedBox(height: 16), TextField(), SizedBox(height: 12), Row( children: [ Expanded(child: TextField()), Icon(Icons.visibility), ], ), SizedBox(height: 16), ElevatedButton( onPressed: () {}, child: Text('로그인하기'), ), ], )

이 예시 하나만 잘 이해해도 Row와 Column의 차이를 꽤 분명하게 잡을 수 있습니다.

결론

Flutter에서 Row와 Column의 차이는 생각보다 단순합니다. Row는 위젯을 가로로 배치할 때 쓰고, Column은 세로로 쌓을 때 씁니다. 처음에는 속성 이름이 낯설 수 있지만, 옆으로 놓을지 아래로 놓을지만 먼저 정하면 훨씬 쉽게 이해됩니다.

실제로 화면을 만들다 보면 둘 중 하나만 쓰는 경우보다 함께 섞어 쓰는 경우가 더 많습니다. 예를 들어 페이지 전체는 Column으로 만들고, 그 안의 아이콘과 텍스트 한 줄은 Row로 넣는 식입니다. 여기에 mainAxisAlignment, crossAxisAlignment, Expanded까지 익혀두면 기본 화면은 충분히 만들 수 있습니다.

처음부터 모든 옵션을 외우려 하기보다, 간단한 예제를 직접 바꿔보면서 차이를 눈으로 확인하는 편이 더 빠릅니다. Flutter 입문 단계에서는 Row와 Column만 제대로 익혀도 화면 배치가 한결 편해집니다.


검증 기준과 참고 자료

이 글은 2026-09-08에 아래 공식 문서와 공개 기술 문서를 기준으로 내용과 용어를 다시 검수했습니다. 제품 버전과 기기 제조사에 따라 화면 이름은 달라질 수 있으므로 실제 화면과 공식 문서를 함께 확인하세요.

관련 글