원문과 함께하는 것을 권장합니다.
중점으로 알아야하는 것
- 위젯은 UI를 빌드하는 데 사용되는 클래스이다.
- 위젯은 레이아웃과 UI 요소 모두에 사용된다.
- 간단한 위젯을 작성하고 조합하여 복잡한 위젯을 작성한다.
Flutter 의 레이아웃 매커니즘의 핵심은 위젯이다. Flutter에서 거의 모든 것이 위젯이며 레이아웃도 위젯이다. Flutter 앱에 표시되는 이미지, 아이콘 및 텍스트는 모두 위젯이다. 보이지 않는 Column, Row, Alignment 등도 위젯이다.
복잡한 위젯을 작성하기 위해 위젯을 조합하여 레이아웃을 작성한다. 원문 아래에 레이아웃을 구성하는 예를 보여준다.
두 번째 스크린 샷은 시각적 레이아웃을 표시하고있고 각 열에는 아이콘과 레이블이 포함된 세개의 열이 존재한다.
이 학습서의 대부분의 스크린샷은 debugPaintSizeEnabled 가 true로 설정되어 표시되므로 시각적 레이아웃 구성을 볼 수 있다.
위에서 보여준 UI 의 위젯트리를 아래 사진에서 보여준다.
앞 튜토리얼을 했으면 예상할 수 있는 구조이다. 하지만 Container 에 대해 궁금할 수 있다. (분홍색으로 표시된 노드) Container는 하위 위젯을 사용자 정의할 수 있는 위젯 클래스이다. padding, margin, border, background 를 추가 할 때 컨테이너를 사용하여 설정할 수 있다.
이 예에서는 각 텍스트 위젯은 Container 에 안에 배치되어 위 margin(예제 사진에서 파란색으로 칠해진 부분) 을 가진다. ??
이 예제의 나머지는 속성에 의해 제어된다. 색상 속성을 사용하여 아이콘의 색상을 설정하고, Text.style 속성을 사용하여 글꼴, 색, 굵기를 설정한다. Row, Column 에너는 자식이 수직 또는 수평으로 정렬되는 방식과 자식의 공간을 지정할 수 있는 속성이 있다.
Flutter 에서 단일 위젯을 어떻게 표현할까? 이 섹션에서는 간단한 위젯을 작성하고 표시하는 방법을 보여준다. 간단한 Hello World 앱의 전체 코드도 보여준다. Flutter 에서는 텍스트, 아이콘 또는 이미지를 화면에 표시하는 데 몇 단계만 거치면 된다.
표시해야할 위젯의 속성(정렬, 제한)에 따라 다양한 레이아웃 중 하나를 선택한다. 이러한 특성을 위젯으로 전달하기 때문이다.
이 예는 내용을 가로 및 세로 가운데 맞추는 Center 를 사용한다.
Text('Hello World'),
Image.asset(
'images/lake.jpg',
fit: BoxFit.cover,
),
Icon(
Icons.star,
color: Colors.red[500],
),
모든 레이아웃은 다음 중 하나가 있다.
Cetner(
child: Text('Hello World'),
),
Flutter 앱 자체는 위젯이고 대부분의 위젯에는 build 메서드가 존재한다. build 메서드에 위젯을 인스턴스화하고 반환하면 위젯이 보여지게 된다.
Material 앱의 경우 Scaffold 위젯을 사용할 수 있다. 기본 배너, 배경 색을 제공하며 Drawers, Snack bars, Bottom Sheet 를 추가할 수 있는 API 를 제공한다. 그런 다음 home 의 body 속성에 Center 위젯을 직접 전달한다.
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter layout demo',
home: Scaffold(
appBar: AppBar(
title: Text('Flutter layout demo'),
),
body: Center(
child: Text('Hello World'),
)
)
)
}
}
Material 앱이 아닌 경우 build 메서드에 Center 위젯을 바로 배치한다.
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: Colors.white),
child: Center(
child: Text(
'Hello World',
textDirection: TextDirection.ltr,
style: TextStyle(
fontSize: 32,
color: Colors.black87,
),
),
),
);
}
}
기본적으로 non-Material 앱에는 AppBar, 제목, 배경 색이 포함되지 않는다. Non-Material 앱에서는 이러한 기능을 사용하려면 직접 작성해야한다. 이 앱은 Material 앱을 모방하기 위해 배경을 흰 색으로, 텍스트를 진한 회색으로 바꾼다.
가장 일반적 패턴 중하나는 위젯을 수직 또는 수평으로 배치하는 것이다. Row 위젯을 사용하여 수평으로 배치하고 Column 위젯을 사용하여 수직으로 배치한다.
중점으로 알아야하는것
- Row 와 Column은 레이아웃 패턴 중 가장 일반적으로 사용된다.
- Row 와 Column은 여러 위젯을 자식으로 갖는다.
- 자식 위젯은 Row, Column 혹은 복잡한 위젯을 가질 수 있다.
- Row 와 Column이 정렬 방법을 지정할 수 있다.
- 하위 위젯의 크기를 늘리거나 조절할 수 있다.
- 하위 위젯이 행 또는 열의 사용 가능한 공간을 사용하는 방법을 지정할 수 있다.
Flutter에서 행 또는 열을 만들려면 하위 위젯 목록을 추가해야한다. children 속성에 들어간 위젯은 행 또는 열에 배치된다. 다음 예제는 Row, Column을 중첩하여 사용하는 방법을 보여준다.
이 레이아웃은 Row로 구성되고, Row에는 두개의 하위 요소가 있다.
왼쪽 Column의 위젯 트리는 Row, Column의 중첩 트리를 가지고있다.
이 예제의 일부를 아래 Nesting rows and column에서 구현한다.
Row 와 Column은 수평 및 수직 배치를 위한 기본 위젯이며, 이러한 낮은 수준의 위젯은 최대로 커스터마이징하게 사용할 수 있다. Flutter는 필요에 따른 전문화되고 더 높은 수준의 위젯을 제공한다. 예를 들어, Row 대신 선행 아이콘과 후행 아이콘에 대한 속성이 포함되어 목록에 사용하기 쉬운 ListTile 을 구현해놨다. Row 대신 사용가능한 공간에 맞추기 위해 내용이 너무 길면 자동으로 스크롤되는 레이아웃인 ListView도 구현되어있다.
mainAxisAlignment 그리고 crossAxisAlignment 속성을 사용하여 Row 또는 Column이 하위 정렬되는 방법을 제어한다. Row의 경우 주 축은 가로, Column의 경우 주 축은 세로가 된다.
MainAxisAlignment 및 CrossAxisAlignment 클래스는 정렬을 제어하기 위한 다양한 상수를 제공한다.
이 예에서 이미지의 각 너비는 100 픽셀이다. 렌더 박스(이 경우 화면 전체)의 너비는 300 픽셀 이상이므로 주축 정렬을 spaceEvenly로 설정하면 빈 수평공간이 각 이미지 사이, 전 후에 균일하게 할당된다.
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Image.asset('image/pic1.jpg'),
Image.asset('image/pic2.jpg'),
Image.asset('image/pic3.jpg'),
]
)
Column은 Row 와 같은 방식으로 작동한다.
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Image.asset('images/pic1.jpg'),
Image.asset('images/pic2.jpg'),
Image.asset('images/pic3.jpg'),
],
);
레이아웃이 너무 커 장치에 맞지 않으면 영향을 받는 가장자리를 따라 노랜색과 검은 색 줄무늬가 나타난다.
Expanded 위젯을 사용하여 Row 또는 Column의 크기에 맞도록 위젯 크기를 조절할 수 있다.
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Image.asset('images/pic1.jpg'),
),
Expanded(
child: Image.asset('images/pic2.jpg'),
),
Expanded(
child: Image.asset('images/pic3.jpg'),
),
],
);
만약 이중 하나의 사진이 더 많은 크기를 차지하게 하고싶다면 flex 속성을 사용한다. Exapanded flex 속성의 기본값은 1이다. 이 값의 비율에 따라 크기를 다르게 가질 수 있다.
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Image.asset('images/pic1.jpg'),
),
Expanded(
flex: 2,
child: Image.asset('images/pic2.jpg'),
),
Expanded(
child: Image.asset('images/pic3.jpg'),
),
],
);
기본적으로 Column Row는 기본 축을 다라 가능한 많은 공간을 차지하지만 자식을 밀접하게 묶으려면 mainAxisSize를 MainAxisSize.min 으로 설정한다. 다음 예는 이 속성을 사용하여 별표 아이콘을 밀접하게 묶는다.
Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.black),
Icon(Icons.star, color: Colors.black),
],
)
레이아웃 프레임워크를 사용하면 원하는만큼 Row와 Column을 중첩할 수 있다. 레이아웃 개요 섹션에 대한 코드의 일부를 작성한다.
위에서 붉은색 부분의 위젯트리는 다음과 같다.
ratings 변수는 5개의 작은 별표 아이콘과 텍스트가 포함된 행을 만든다.
var stars = Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.black),
Icon(Icons.star, color: Colors.black),
],
);
final ratings = Container(
padding: EdgeInsets.all(20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
stars,
Text(
'170 Reviews',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w800,
fontFamily: 'Roboto',
letterSpacing: 0.5,
fontSize: 20,
),
),
],
),
);
많이 중첩된 레이아웃 코드로 인해 발생할 수 있는 시각적 혼란을 최소화하려면 변수 및 함수에서 구현 후 조합한다.
위젯트리에서 rating 아래에는 각 열에는 아이콘과 두 줄의 텍스트가있다.
final descTextStyle = TextStyle(
color: Colors.black,
fontWeight: FontWeight.w800,
fontFamily: 'Roboto',
letterSpacing: 0.5,
fontSize: 18,
height: 2,
);
// ??
final iconList = DefaultTextStyle.merge(
style: descTextStyle,
child: Container(
padding: EdgeInsets.all(20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Column(
children: [
Icon(Icons.kitchen, color: Colors.green[500]),
Text('PREP:'),
Text('25 min'),
],
),
Column(
children: [
Icon(Icons.timer, color: Colors.green[500]),
Text('COOK:'),
Text('1 hr'),
],
),
Column(
children: [
Icon(Icons.restaurant, color: Colors.green[500]),
Text('FEEDS:'),
Text('4-6'),
],
),
],
),
),
);
각 UI 트리를 정의한 것을 leftColumn 에서 합친다.
final leftColumn = Container(
padding: EdgeInsets.fromLTRB(20, 30, 20, 20),
child: Column(
children: [
titleText,
subTitle,
ratings,
iconList,
],
),
)
왼쪽 Column은 너비를 제한하기 위해 컨테이너에 배치한다. 마지막으로 UI 는 카드로 구성한다.
body: Center(
child: Container(
margin: EdgeInsets.fromLTRB(0, 40, 0, 30),
height: 600,
child: Card(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 440,
child: leftColumn,
),
mainImage,
],
),
),
),
),
Flutter의 위젯 라이브러리에는 다양하게 존재한다. 가장 일반적으로 사용되는게 몇 있는데, 이를 사용하여 가장 빠르게 시작할 수 있다. 사용가능한 다른 위젯 정보는 다른 것을 참조한다.
위젯은 표준 위젯과 Material 위젯의 두가지 범주로 분류된다. 모든 앱은 위젯 라이브러리를 사용할 수 있지만 Material 컴포넌트는 Material 앱에서만 사용할 수 있다.
위 위젯들이 어떻게표시되는지는 원문을 보자. 어떤 UI가 존재하는지 알면 된다.