latout 만들기
Flutter의 레이아웃 메커니즘이 동작하는 방식을 이해하고 UI를 설계하는 방법을 연습해보자.
화면 쪼개기
이와 같은 형태의 화면을 구현하고자 한다고 가정해보자
- 화면의 구성요소에서
Column
이나Row
를 추출해보자. Grid
구성요소가 있는지 확인하자.- 겹쳐진 구성요소는 없는가?
- 탭을 필요로하는가?
alignment
,padding
또는borders
같은 부분이 필요한지 살피자
우선 화면을 큰 구성요소로 쪼개보면 아래와 같은 레이아웃을 생각 할 수 있다. 즉 4개의 하위 요소를 가지는 하나의 Column
으로 구성된다. 그 하위 요소들은 각각 하나의 이미지 요소, 두개의 Row
요소 그리고 하나의 Text
요소로 볼 수 있다.
- 하위요소로 잘게 쪼개기 : 첫번쨰 row 는 (상부의 이미지에 대한 타이틀을 기록한 것으로 보이므로 임의로 title 영역이라고 부르자) 아래와 같이 세개의 하위 요소로 쪼갤 수 있다. 이떄 그 첫번쨰 하위 요소는 다시 두개의 하위 text 요소로 구성된
Column
요소로 볼 수 있고 그 다음은Icon
요소 와Text
요소 (숫자 요소)로 구성된다.Column
요소는 우측에 많은 여백을 가지므로 이를 구현할 수있는Expaned
위젯을 사용해야 한다.
두번째 row는 (Button section) 세개의 하위 요소로 쪼갤 수 있으며 이들은 모두 두개의 하위 요소를 가지는 Column
요소로 볼 수 있다. 세개의 Column
요소들은 모두 상부에 Icon요소 하부에 Text 요소를 가지고 있다.
flutter 기본앱 코드작성하기
코드를 구현하기에 앞서 일단 IDE (VS CODE)를 이용해 flutter 기본앱 코드를 입력한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter layout demo',
home: Scaffold(
appBar: AppBar(
title: const Text('Flutter layout demo'),
),
body: const Center(
child: Text('Hello World'),
),
),
);
}
}
column 위젯 구현
body 위치의 Center 위젯 대신에 아래의 Column위젯을 구현하여 대체한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
Column(
children: [
Image.asset( // imageSection
'images/lake.jpg',
width: 600,
height: 240,
fit: BoxFit.cover,
),
titleSection,
buttonSection,
textSection,
],
)
이제 하위 요소인 네개의 위젯 만 (imageSection, titleSection, buttonSection, textSection) 구체적으로 구현해 주면 된다. imageSection은 예제와 같이 이미 정의된 Image
위젯을 이용해 구현할 수 있다. 다만 .asset
이 구현되기 위해서는 프로젝트 폴더의 최상위 디렉토리에 images
폴더를 생성한 후에 여기에 lake.jpg 이미지를 다운 받아 카피해 넣어준다. pubspec.yaml
파일을 열어서 flutter
위치에 아래와 같이 입력해준다.
1
2
3
4
flutter:
uses-material-design: true
assets:
- images/lake.jpg
fit:BoxFit.cover
는 가능한 작게, 하지만 렌더링 박스 전체를 덮을 정도로만 작아야 한다는 것을 프레임워크에 알려준다.
titleSection 위젯 구현
아래와 같은 코드를 Build 위젯의 가장 윗 부분에 넣어 준다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Widget titleSection = Container(
padding: const EdgeInsets.all(32),
child: Row(
children: [
Expanded(
/*1*/
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
/*2*/
Container(
padding: const EdgeInsets.only(bottom: 8),
child: Text(
'Oeschinen Lake Campground',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
),
Text(
'Kandersteg, Switzerland',
style: TextStyle(
color: Colors.grey[500],
),
),
],
),
),
/*3*/
Icon(
Icons.star,
color: Colors.red[500],
),
Text('41'),
],
),
);
앞에서 레이아웃을 설정할 때 언급했던 것 같이 전체 Row는 Container안에 들어 있고, 사방으로 32 pixel의 패딩이 설치된다. Row 위젯이 하위 요소로 구성된다.
Row 위젯 내부에는 Expanded
와 Icon
, Text
위젯을 설치한다.
/* 1 */
Expanded 위젯의 width는 다른 요소들이 차지하고 남는 공간을 모두 점유하는 특징을 가진다. 따라서 그 안에 Column을 넣고crossAxisAlignment property
를CrossAxisAlignment.start
로 설정하면 Column이 Row의 시작 위치에 배치되고 Row의 우측에 다른 요소가 차지하고 남은 공간까지를 Expanded 위젯이 점유하므로 그 공간은 빈칸으로 채워진다./* 2 */
첫 번째 Row의 텍스트를 Container로 감싸주면 그 내부에padding
을 설정할 수 있다. Column의 두 번째 하위요소는 글자색을 gray[500]으로 설정했다./* 3 */
Icon은star
하위요소로 정의하고 색상은 Color의 하위요소를 red[500] 선택한여 설정한다. 우측의Text
에는 숫자41
을 넣는다.
bottonSection 위젯 구현
버튼 영역은 모두 동일하게 텍스트 위에 아이콘을 배치한 column 레이아웃 3개를 담고 있다. 이 Row의 Column은 모두 동일한 영역을 차지한다. 또한 텍스트와 아이콘은 기본 색으로 그려진다.
각 컬럼의 코드가 거의 동일하기 때문에, 색상과, 아이콘, 그리고 텍스트를 인수로 받아 주어진 색으로 칠한 위젯을 반환하는 _buildButtonColumn()
이라는 private 헬퍼 메소드를 생성하는 것이 코드를 간략하게 하는데 도움이 된다.(변수명 앞에 underbar(_)는 private 변수임을 나타낸다) 메소드의 코드는 아래와 같다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Column _buildButtonColumn(Color color, IconData icon, String label) {
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(icon, color: color),
Container(
margin: const EdgeInsets.only(top: 8),
child: Text(
label,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w400,
color: color,
),
),
),
],
);
}
이 함수는 아이콘을 Column 속에 직접 넣는다. 텍스트는 아이콘과 간격을 주기위해 상단 마진이 필요하므로 Container 위젯 속에 넣는다.
이제 이 함수를 호출해서 버튼섹션을 구성해보자.
1
2
3
4
5
6
7
8
9
10
11
12
Color themeColor = Theme.of(context).primaryColor;
Widget buttonSection = Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_buildButtonColumn(themeColor, Icons.call, 'CALL'),
_buildButtonColumn(themeColor, Icons.near_me, 'ROUTE'),
_buildButtonColumn(themeColor, Icons.share, 'SHARE'),
],
),
);
- Theme 위젯
테마위젯은 응용 프로그램의 색상과 활자 선택에 대해 서술한다. 하위 위젯으로 [Theme.of]를 사용하여 현재 테마의 [ThemeData] 개체를 가져온다. 이렇게 하면 추후 테마가 변경되었을 때 자동으로 재 구축되어 그 변경 사항이 적용될 수 있도록 한다.
[Theme] 위젯은 [Theme]에 대한 [data]의 [ThemeData.iconTheme] 값으로 설정된 [IconTheme] 위젯을 의미한다.
이 함수에 해당 column을 위한 색상, Icon 종류와 그 이름을 함께 호출해서 Row
를 작성한다. main axis의 정렬은 column들이 모두 동일한 영역을 차지하도록 MainAxisAlignment.spaceEvenly
를 사용한다.
Text Section 작성
textSection
은 사면에 적당한 크기의 여백을 주는 것, 텍스트가 폭방향으로 채워지면 자동으로 줄 바꿈하는 기능 이외에는 다른 처리가 필요없다. Container안에 32픽셀 크기의 padding을 넣고 Text
위젯 안에 필요한 텍스트를 넣어주는 것으로 끝이다. 하기의 코드를 bottonSection위젯 아래에 넣어준다.
1
2
3
4
5
6
7
8
9
10
11
12
Widget textSection = Container(
padding: const EdgeInsets.all(32),
child: const Text(
'Lake Oeschinen lies at the foot of the Blüemlisalp in the Bernese '
'Alps. Situated 1,578 meters above sea level, it is one of the '
'larger Alpine Lakes. A gondola ride from Kandersteg, followed by a '
'half-hour walk through pastures and pine forest, leads you to the '
'lake, which warms to 20 degrees Celsius in the summer. Activities '
'enjoyed here include rowing, and riding the summer toboggan run.',
softWrap: true,
),
);
여기서 softWrap: true
는 글이 column 끝까지 채워지면 자동으로 줄바꿈하는 역할을 한다.
가상 디바이스에서 App 실행 해보기
가상 디바이스는 Android Studio에서 설치해야 한다. 여러 다른 자료들을 참조하여 적당한 device를 설치한다. VS CODE의 경우 아래 그림처럼 화면 우측하단에 Windows(windows-x64)
라고 표시된 곳을 마우스 클릭하면 상단에 작은 device 입력창이 나타나는데 여기서 이미 설치한 device를 선택한다.(만일 우측하단에 No Device 라고 뜨면 Ctrl + Shift + p
키를 누르고 상단에 나온 입력창에 Flutter:Launch Emulatot
또는 Flutter:Select Device
라고 입력하면 디바이스 선택창이 나온다.)
디바이스를 선택하면 화면에
- 스마트폰 형상의 에뮬레이터가 나타나고 우측하단의
Windows(windows-x64)
표시가 선택한 디바이스 명으로 변경된다. - 좌측 하단에 프로젝트 폴더명
flutter_application_1
이 보이는데 그 옆에(release mode)
또는(profile mode)
라고 쓰여 있다면 - 좌측 상단 삼각형
run
단추 옆의 아래 꺽쇠를 눌러flutter_application_1
로 선택해준다. 이후에 2.3.4.번 중 어느하나의 삼각형 런단추를 누르면 프로그램이 진행된다
크로그램이 진행됨에 따라서 콘솔창에 순차적으로 그림과 같은 메시지가 나타나고 디바이스 창에 목표하는 화면이 얻어진것을 볼 수 있다.
대개의 경우 이 상태에서 코드를 변경한 후에 이를 저장(Ctrl + s)하면 변경된 내용이 Hot reload 되면서 자동으로 반영된다.
ListView 위젯
만일 보다 작은 디바이스에서 스크롤 방식으로 화면작동이 가능하도록 하고 싶다면 body에서 사용한 Column
위젯을 ListView
로 바꿔주면 된다.
column위젯 사용 | ListView 위젯 사용 |
만일 화면의 크기가 필요한 높이보다 작은 경우 column위젯은 왼쪽 그림처럼 에러가 발생하지만 ListView 위젯을 사용하는 경우 우측 그림에서 처럼 모자라는 영역은 아래쪽에 감춰지면서 스크롤 바가 표시되고 스크롤바를 움직이면 아래쪽을 볼 수 있게 된다.
Comments powered by Disqus.