위젯 소개
Flutter 위젯은 React에 영감을 얻어 구축되었다.
Flutter는 위젯으로 UI를 구성합니다.
1. Container
아무것도 없는 위젯으로 컨테이너 위젯을 사용하여 직사각형 시각적 요소를 작성할 수 있다.
컨테이너는 여백, 패딩, 가로, 세로 등 적용할 수 있다.
또한, 매트릭스를 사용한 3차원 공간에서 변환과 BoxDecoration으로 배경, 테두리, 그림자 등을 장식할 수 있고 child 프로퍼티로 다른 위젯을 자식으로 가질 수 있다.
다음은 Scaffold의 body 프로퍼티에 container를 작성한 예제이다.
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Hello World'),
),
body: Container(
color: Colors.red,
width: 100,
height: 100,
));
}
}
2. Column & Row
레이아웃 대부분은 column과 row를 조합하여 만듭니다.
Column과 Row은 children 프로퍼티에 여러 위젯을 나열하며 웹의 Flexbox 배치 모델을 기반으로 합니다.
2.1 Column
Column({Key? key, MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start, MainAxisSize mainAxisSize = MainAxisSize.max, CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center, TextDirection? textDirection, VerticalDirection verticalDirection = VerticalDirection.down, TextBaseline? textBaseline, List<Widget> children = const <Widget>[]})
column은 수직(열) 방향으로 유연한 레이아웃을 작성할 수 있습니다.
children 프로퍼티에는 여러 위젯의 리스트를 지정할 수 있으며 지정한 위젯들은 세로로 배치된다.
column 위젯은 스크롤이 되지 않습니다.
다음은 column 위젯의 간단한 예제입니다.
Column(
children: const <Widget>[
Text('Deliver features faster'),
Text('Craft beautiful UIs'),
Expanded(
child: FittedBox(
fit: BoxFit.contain, // otherwise the logo will be tiny
child: FlutterLogo(),
),
),
],
)
2.2. Row
Row({Key? key, MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start, MainAxisSize mainAxisSize = MainAxisSize.max, CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center, TextDirection? textDirection, VerticalDirection verticalDirection = VerticalDirection.down, TextBaseline? textBaseline, List<Widget> children = const <Widget>[]})
column과 반대로 row은 수평(행) 방향으로 유연한 레이아웃을 작성할 수 있습니다.
children 프로퍼티에는 여러 위젯의 리스트를 지정할 수 있으며 지정한 위젯들은 가로로 배치된다.
row위젯은 스크롤이 되지 않습니다.
다음은 row 위젯의 간단한 예제입니다.
Row(
children: const <Widget>[
Expanded(
child: Text('Deliver features faster', textAlign: TextAlign.center),
),
Expanded(
child: Text('Craft beautiful UIs', textAlign: TextAlign.center),
),
Expanded(
child: FittedBox(
fit: BoxFit.contain, // otherwise the logo will be tiny
child: FlutterLogo(),
),
),
],
)
- row과 column과 같은 방향성이 있는 위젯은 mainAxis와 crossAxis 관련 프로퍼티가 있다.
mainAxis
위젯의 기본 방향을 나타낸다. row은 오른쪽, column은 아래쪽이 mainAxis가 된다.
crossAxis
기본 방향의 반대 방향을 나타낸다. row는 아래쪽 column은 오른쪽이 crossAxis가 된다.
각 프로퍼티에 지정할 수 있는 상수는 다음과 같다.
MainAxisSize에 정의된 상수
max | 최대 크기, 남은 공간 모두 차지 |
min | 최소 크기, 포함된 콘텐츠의 크기만큼 차지 |
MainAxisAlignment와 CrossAxisAlignment에 정의된 상수
center | 가운데 정렬 |
start | 왼쪽 정렬 |
end | 오른쪽 정렬 |
spaceEvenly | 각 위젯의 공간을 앞뒤로 균등하게 나눔 |
spaceBetween | 각 위젯의 공간을 균등하게 나누지만, 양끝에 여백이 없이 정렬 |
spaceAround | 각 위젯의 공간을 균등하게 나누지만, 첫 번째 자식 앞과 마지막 자식 뒤의 공간의 폭을 절반으로 줄인다. |
3. Stack
stack은 웹의 absolute positioning 레이아웃 모델을 기반으로 합니다.
그래서 선형 방향 (수평 또는 수직)이 아닌 위젯을 순서대로 겹치게 배치할 수 있습니다.
그런 다음 스택의 하위 항목에 배치 위젯을 사용하여 스택의 위쪽, 오른쪽, 아래쪽 또는 왼쪽 가장자리에 상대적으로 배치할 수 있습니다.
children 프로퍼티에 정의한 리스트에 먼저 작성한 위젯이 가장 아래쪽에 위치하고 나중에 작성한 위젯이 위쪽에 위치합니다.
Positioned을 사용하면 Stack내에서 특정 하위 요소에 특정 위치를 지정할 수 있다. 또한, stack은 경계선 밖으로 하위 위젯을 밀어낼 수 있고 overflow 속성을 사용해 경계선을 벗어날지 말지를 통제할 수 있다.
다음은 stack 위젯의 예제입니다.
Stack(
children: <Widget>[
Container(
width: 100,
height: 100,
color: Colors.red,
),
Container(
width: 90,
height: 90,
color: Colors.green,
),
Container(
width: 80,
height: 80,
color: Colors.blue,
),
],
)
4. SingleChildScrollView
화면 크기를 넘어서면 스크롤이 필요할 때 SingleChildScrollView로 감싸면 스크롤이 가능하게 하는 위젯입니다.
하위 목록이 있고 화면 너비가 항상 스크롤되는 목록 등 동작이 필요하지 않은 경우 ListView를 사용하는 게 좋다.
다음은 SingleChildScrollView의 예제이다.
class _MyHomePageState extends State<MyHomePage> {
final items = List.generate(100, (i) => i).toList();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Hello World'),
),
body: SingleChildScrollView(
child: ListBody(children: items.map((i) => Text('$i')).toList()),
));
}
}
5. ListView, ListTile
ListView는 리스트를 표시하는 위젯이다.
ListView의 경우는 스크롤을 내리면 추가적으로 렌더링을 하고 SingleChildScrollView의 경우 보일 모든 위젯을 렌더링 하기 때문에
동일하게 스크롤 효과를 내리지만 ListView은 SingleChildScrollView보다 리스트에 최적화된 위젯이다.
ListView는 수평 또는 수직으로 리스트를 배치할 수 있다.
상향식 접근법(아래에서 위)를 선호한다면 reverse: true로 설정한다.
스크롤이 되지 않게 설정하고 싶은 경우 physics: NeverScrollableScrollPhysics()로 설정하면 된다.
화면에 표시되지 않은 항목들을 사용하고 싶지 않는 경우 addAutomaticKeepAlives: false를 하면 된다.
화면 밖의 수단에 대해 어느 정도의 제어를 하고 싶다면 cacheExtent를 사용한다.
cacheExtent은 픽셀 단위로 지정할 수 있으며 캐시 영역에 있는 항목은 화면에 표시되지 않더라도 레이아웃이 된다.
동적으로 리스트를 보여주고 싶으면 ListView.builder를 사용하면 된다.
body: ListView.builder(
itemBuilder: (items, index) => Text('$index'),
)
만약 리스트의 구분선을 넣고 싶으면 ListView.builder이 아닌 ListView.separated를 사용하면 된다.
ListView.separated를 사용하기 위해서는 리스트에 몇 개의 항목이 있는지만 기억하면 된다.
ListView.separated(
itemBuilder: (items, index) => Text('$index'),
separatorBuilder: (items, index) => Divider(),
itemCount: items.length,
)
ListView.custom으로 ListView를 제작할 수 있다.
ListTile을 사용하면 최대 3줄의 텍스트와 선택적 선행 및 후행 아이콘이 포함된 행을 쉽게 작성할 수 있다.
ListTile은 Crad와 ListView위젯에서 일반적으로 사용하지만 다른 위젯에서도 사용할 수 있다.
ListTile은 leading, title, trailing 프로퍼티가 각 왼쪽, 중앙, 오른쪽 위치를 담당한다.
onTap이나 onLongPress 콜백과도 상호 작용이 된다.
subtitle프로퍼티는 title 밑에 줄을 추가할 때 사용할 수 있으며 isThreeLine을 true로 할 경우 3줄을 사용할 수 있다.
dense속성을 이용하면 전체적으로 작게 밀집시킬 수 있다.
enabled 또는 selected속성으로 타일을 꾸밀 수 있다.
horizontalTitleGap은 trailing와 title의 간격을 조절할 수 있다.
다음은 ListTile의 예제이다.
body: ListView(
scrollDirection: Axis.vertical,
children: <Widget>[
ListTile(
leading: Icon(Icons.home),
title: Text('Home'),
trailing: Icon(Icons.navigate_next),
)
],
)
6. GridView
GridView는 일반적인 갤러리처럼 열 수를 지정하여 그리드 형태로 표시하는 위젯이다.
많은 생성자들 중 GridView.count()가 많이 쓰이는데, 이 생성자는 간단하게 그리드를 작성할 수 있다.
crossAxisCount로 열 수를 지정할 수 있다.
mainAxisSpacing로 행 사이의 수평 공간을 설정할 수 있고
crossAxisSpacing는 열 사이의 수직 공간을 설정한다.
GradView는 ListView처럼 항목들을 스크롤할 수 있다.
다음은 GradView의 예제이다.
GridView.count(
crossAxisCount: 4,
crossAxisSpacing: 5.0,
mainAxisSpacing: 5.0,
childAspectRatio: 1.0,
children: List.generate(items.length, (index) {
return Container(
color: Colors.blue,
child: Text("$index"),
);
})))
7. PageView
여러 화면을 좌우로 슬라이드 하여 넘길 수 있는 위젯이다.
children 프로퍼티에 각 화면에 표현할 위젯을 지정하면 위젯으로 화면을 슬라이드 할 수 있지만,
PageController로 뷰에 표시되는 페이지를 제어할 수 있어 PageView와 PageController을 사용하면 사용자들이 마음에 드는 콘텐츠까지 스와이프 할 수 있다.
PageView 예제는 다음과 같다
final PageController controller = PageController();
...
PageView(
controller: controller,
children: const <Widget>[
Center(
child: Text('First Page'),
),
Center(
child: Text('Second Page'),
),
Center(
child: Text('Third Page'),
)
],
)
8. AppBar, TabBar, Tab, TabBarView를 이용한 탭이 연동되는 화면
TabBar는 탭의 수평 행을 표시하는 위젯으로 일반적으로 TabBarView와 함께 AppBar의 하단 부분에 생성됩니다.
TabController로 하지 않는 경우 DefaultTabController 상위 항목을 제공해야 하며 탭 컨트롤러의 length는 목록의 길이와 TabBarView.children 목록의 길이와 같아야 합니다.
다음은 AppBar, TabBar, Tab, TabBarView를 결합한 위젯 예제이다.
@override
Widget build(BuildContext context) {
return DefaultTabController(
initialIndex: 1,
length: 3,
child: Scaffold(
appBar: AppBar(
title: const Text('TabBar Widget'),
bottom: const TabBar(
tabs: <Widget>[
Tab(
icon: Icon(Icons.cloud_outlined),
),
Tab(
icon: Icon(Icons.beach_access_sharp),
),
Tab(
icon: Icon(Icons.brightness_5_sharp),
),
],
),
),
body: const TabBarView(
children: <Widget>[
Center(
child: Text("It's cloudy here"),
),
Center(
child: Text("It's rainy here"),
),
Center(
child: Text("It's sunny here"),
),
],
),
),
);
}
탭에는 아이콘이나 글자를 표시할 수 있으며 탭이 있어 PageView만 단독으로 사용하는 것보다 사용성을 높일 수 있다.
9. BottomNavigationBar
BottomNavigationBar는 하단에 2~5개의 탭 메뉴를 구성할 수 있는 위젯으로 각 탭을 클릭하여 화면을 전환할 때 사용한다.
BottomNavigagtionBar는 일반적으로 Scffold와 함께 사용하며 Scaffold.bottomNavigationBar로 제공한다.
bottomNavigationBar를 정의하면 items 프로퍼티에 BottomNavigationBarItem 위젯을 나열하고 icon과 label 프로퍼티를 정의하면 간단한 하단 탭바를 구성할 수 있다.
다음은 BottomNavigationBar의 위젯 예제이다.
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final PageController controller = PageController();
int _selectedIndex = 0;
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
static const List<Widget> _widgetOptions = <Widget>[
Text(
'Index 0: Home',
style: optionStyle,
),
Text(
'Index 1: Business',
style: optionStyle,
),
Text(
'Index 2: School',
style: optionStyle,
),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('BottomNavigationBar Sample'),
),
body: Center(
child: _widgetOptions.elementAt(_selectedIndex),
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
label: 'Business',
),
BottomNavigationBarItem(
icon: Icon(Icons.school),
label: 'School',
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.amber[800],
onTap: _onItemTapped,
),
);
}
}
[참고]
Flutter - 가장 빠른 아름다운 네이티브 앱
Flutter(플러터)는 하나의 코드베이스로 모바일, 웹, 데스크톱에서 네이티브로 컴파일 되는 구글의 아름다운 UI 툴킷입니다. Flutter는 기존 코드와 함께 동작하고, 전세계 개발자와 조직에 쓰이고
flutter-ko.dev
2. 소문난 명강의: 오준석의 플러터 생존코딩
'IT > 기록' 카테고리의 다른 글
Flutter 여백을 주는 위젯 (0) | 2022.05.17 |
---|---|
관계형 데이터베이스란? (0) | 2022.05.02 |
포토샵 대용으로 쓸만한 프로그램 김프(GIMP) 설치 후 무료폰트 적용하기 (0) | 2022.02.11 |
[Flutter] Firebase Cloud Firestore 사용하기 #2 컬렉션 생성 (0) | 2021.08.21 |
[Flutter] Firebase Cloud Firestore 사용하기 #1 데이터베이스 만들기 (0) | 2021.08.21 |