개요
Column은 자식 위젯들을 수직 방향으로 배치하는 레이아웃 위젯입니다.
Column은 Flex 위젯의 편의 래퍼로, 방향이 수직으로 고정되어 있습니다. 여러 위젯을 세로로 나란히 배치할 때 사용하며, 다양한 정렬 옵션을 제공합니다. 기본적으로 Column은 가능한 모든 수직 공간을 차지하지만, mainAxisSize
를 조정하여 필요한 만큼만 차지하도록 설정할 수 있습니다.
언제 사용하나요?
- 폼 필드를 세로로 나열할 때
- 리스트 아이템의 내용을 구성할 때
- 카드나 다이얼로그의 수직 레이아웃을 만들 때
- 메뉴 항목을 세로로 배치할 때
- 제목, 부제목, 본문을 순서대로 표시할 때
기본 사용법
// 간단한 예제
const column = Column({
children: [
Text('Title'),
Text('Subtitle'),
Text('Body')
]
});
// 정렬 옵션 사용
const alignedColumn = Column({
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('왼쪽 정렬된'),
Text('세로 가운데'),
Text('텍스트들')
]
});
Props
children (필수)
값: Widget[]
Column에 표시할 자식 위젯들의 배열입니다. 배열 순서대로 위에서 아래로 배치됩니다.
Column({
children: [
Container({ width: 100, height: 50, color: 'red' }),
Container({ width: 100, height: 50, color: 'green' }),
Container({ width: 100, height: 50, color: 'blue' })
]
})
mainAxisAlignment
값: MainAxisAlignment (기본값: MainAxisAlignment.start)
자식 위젯들의 수직 정렬 방식을 정의합니다.
- start: 상단 정렬 (기본값)
- end: 하단 정렬
- center: 가운데 정렬
- spaceBetween: 첫 번째와 마지막 위젯을 양 끝에 배치하고 나머지 공간을 균등 분배
- spaceAround: 각 위젯 주변에 균등한 공간 분배
- spaceEvenly: 모든 위젯과 가장자리 사이의 공간을 균등 분배
// 가운데 정렬
Column({
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('A'),
Text('B'),
Text('C')
]
})
// 공간 균등 분배
Column({
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Icon({ icon: Icons.home }),
Icon({ icon: Icons.search }),
Icon({ icon: Icons.settings })
]
})
crossAxisAlignment
값: CrossAxisAlignment (기본값: CrossAxisAlignment.center)
자식 위젯들의 수평 정렬 방식을 정의합니다.
- start: 왼쪽 정렬
- end: 오른쪽 정렬
- center: 가로 가운데 정렬 (기본값)
- stretch: 사용 가능한 가로 공간을 모두 차지하도록 늘림
Column({
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container({ width: 100, height: 50, color: 'red' }),
Container({ width: 150, height: 50, color: 'green' }),
Container({ width: 75, height: 50, color: 'blue' })
]
})
mainAxisSize
값: MainAxisSize (기본값: MainAxisSize.max)
Column이 차지하는 수직 공간의 크기를 제어합니다.
- max: 사용 가능한 모든 수직 공간을 차지 (기본값)
- min: 자식 위젯들에 필요한 최소 공간만 차지
// 필요한 공간만 차지
Container({
color: 'lightgray',
child: Column({
mainAxisSize: MainAxisSize.min,
children: [
Text('Compact'),
Text('Column')
]
})
})
verticalDirection
값: VerticalDirection (기본값: VerticalDirection.down)
자식 위젯들의 수직 배치 순서를 정의합니다.
- down: 위에서 아래로 (기본값)
- up: 아래에서 위로
Column({
verticalDirection: VerticalDirection.up,
children: [
Text('1번'), // 맨 아래 표시
Text('2번'), // 중간 표시
Text('3번') // 맨 위 표시
]
})
고급 사용법
Expanded와 함께 사용하기
Column({
children: [
Container({ width: 100, height: 50, color: 'red' }),
Expanded({
child: Container({ width: 100, color: 'green' })
}),
Container({ width: 100, height: 50, color: 'blue' })
]
})
// 녹색 Container가 남은 수직 공간을 모두 차지합니다
비율로 공간 분배하기
Column({
children: [
Flexible({
flex: 1,
child: Container({ color: 'red' })
}),
Flexible({
flex: 2,
child: Container({ color: 'green' })
}),
Flexible({
flex: 1,
child: Container({ color: 'blue' })
})
]
})
// 빨간색 25%, 녹색 50%, 파란색 25%의 높이를 차지합니다
실제 사용 예제
예제 1: 로그인 폼
const loginForm = Container({
padding: EdgeInsets.all(20),
child: Column({
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text('로그인', {
style: TextStyle({ fontSize: 24, fontWeight: 'bold' })
}),
SizedBox({ height: 30 }),
TextField({
decoration: InputDecoration({
labelText: '이메일',
border: OutlineInputBorder()
})
}),
SizedBox({ height: 16 }),
TextField({
obscureText: true,
decoration: InputDecoration({
labelText: '비밀번호',
border: OutlineInputBorder()
})
}),
SizedBox({ height: 24 }),
ElevatedButton({
onPressed: () => console.log('로그인'),
child: Text('로그인')
}),
SizedBox({ height: 16 }),
TextButton({
onPressed: () => console.log('회원가입'),
child: Text('계정이 없으신가요? 회원가입')
})
]
})
});
예제 2: 카드 컨텐츠
const card = Container({
margin: EdgeInsets.all(16),
padding: EdgeInsets.all(16),
decoration: BoxDecoration({
color: 'white',
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow({
color: 'rgba(0, 0, 0, 0.1)',
blurRadius: 10,
offset: { x: 0, y: 4 }
})
]
}),
child: Column({
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image({
src: 'product.jpg',
height: 200,
fit: 'cover'
}),
SizedBox({ height: 16 }),
Text('상품명', {
style: TextStyle({ fontSize: 20, fontWeight: 'bold' })
}),
SizedBox({ height: 8 }),
Text('상품 설명이 여기에 표시됩니다...', {
style: TextStyle({ color: 'gray' })
}),
SizedBox({ height: 16 }),
Row({
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('₩25,000', {
style: TextStyle({ fontSize: 18, fontWeight: 'bold', color: 'blue' })
}),
IconButton({
icon: Icons.favorite_border,
onPressed: () => {}
})
]
})
]
})
});
예제 3: 설정 메뉴
const settingsMenu = Column({
children: [
ListTile({
leading: Icon({ icon: Icons.person }),
title: Text('프로필'),
trailing: Icon({ icon: Icons.arrow_forward_ios }),
onTap: () => console.log('프로필')
}),
Divider(),
ListTile({
leading: Icon({ icon: Icons.notifications }),
title: Text('알림'),
trailing: Switch({
value: true,
onChanged: (value) => {}
})
}),
Divider(),
ListTile({
leading: Icon({ icon: Icons.lock }),
title: Text('개인정보 보호'),
trailing: Icon({ icon: Icons.arrow_forward_ios }),
onTap: () => console.log('개인정보')
}),
Divider(),
ListTile({
leading: Icon({ icon: Icons.help }),
title: Text('도움말'),
trailing: Icon({ icon: Icons.arrow_forward_ios }),
onTap: () => console.log('도움말')
})
]
});
주의사항
- Column 내부의 자식 위젯이 세로 공간을 초과하면 오버플로우 오류가 발생합니다. 이런 경우
SingleChildScrollView
로 감싸거나Flexible
/Expanded
를 사용하세요. crossAxisAlignment.stretch
를 사용할 때, 자식 위젯의 너비가 제한되지 않으면 무한히 늘어날 수 있습니다.- Column은 스크롤을 지원하지 않습니다. 스크롤이 필요한 경우
SingleChildScrollView
또는ListView
를 사용하세요. - 가로 방향 레이아웃이 필요한 경우
Row
위젯을 사용하세요.
관련 위젯
- Row: 자식 위젯을 가로로 배치
- Flex: Column과 Row의 기반이 되는 더 유연한 레이아웃 위젯
- ListView: 스크롤 가능한 세로 리스트
- Stack: 자식 위젯을 겹쳐서 배치
- Expanded: Column 내에서 남은 공간을 차지
- Flexible: Column 내에서 유연한 크기 조정