일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- sqlite
- Flutter 강좌
- flutter
- 반석천
- navigator
- Flutter 앱 배포
- Flutter 예제
- FutureBuilder
- Column Widget
- Networking
- listview
- Row Widget
- WillPopScope
- Cached Image
- Image.network
- Flutter Example
- AppBar
- HTTP
- ListView.builder
- Snackbar
- Row
- Load Image
- CrossAxisAlignment
- ListTile
- Scaffold
- InkWell
- node.js
- MainAxisAlignment
- Flutter Tutorial
- Hello World
- Today
- Total
꿈꾸는 시스템 디자이너
Flutter 강좌 - Layout Tutorial | 레이아웃 구성 본문
Flutter 강좌 목록 : https://here4you.tistory.com/120
1 단계 - 코드 기반의 앱을 생성
우선 다음과 같은 코드를 작성한다.
import 'package:flutter/material.dart';
// MyApp을 시작 위젯으로 설정하여 앱을 실행
void main() => runApp(MyApp());
// 앱의 시작점에 해당하는 위젯
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 매트리얼앱을 생성하여 반환
return MaterialApp(
title: 'Flutter Layout Demo', // 앱의 타이틀
theme: ThemeData( // 앱의 테마 설정
primarySwatch: Colors.red, // 주요 테마 색상
),
// 홈 설정. 홈은 메트리얼앱의 시작점
home:Scaffold(
appBar: AppBar(
title: Text("Flutter layout demo"),
),
body: Center(
child: Text("Hello World"),
),
)
);
}
}
소스코드는 기존 강좌에서 살펴본 코드와 비슷한 구성입니다. 메인함수에서 runApp 함수를 통해 MyApp 위젯을 호출합니다. MyApp 위젯은 매트리얼앱을 생성하여 반환하여 앱이 화면에 출력되게 된다.
상기 코드의 실행화면은 다음과 같다.
2 단계 - 타이틀 로우 구현
앞서 작성한 코드를 다음과 같이 추가 수정한다.
import 'package:flutter/material.dart';
// MyApp을 시작 위젯으로 설정하여 앱을 실행
void main() => runApp(MyApp());
// 앱의 시작점에 해당하는 위젯
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 매트리얼앱을 생성하여 반환
return MaterialApp(
title: 'Flutter Layout Demo', // 앱의 타이틀
theme: ThemeData( // 앱의 테마 설정
primarySwatch: Colors.red, // 주요 테마 색상
),
// 홈 설정. 홈은 메트리얼앱의 시작점
home:Scaffold(
appBar: AppBar(
title: Text("Flutter layout demo"),
),
// 기존 body 삭제
// body: Center(
// child: Text("Hello World"),
// ),
// 새로운 body 선언
body: Column( // 컬럼으로 교체
// 자식들을 추가
children: <Widget>[
titleSection // titleSection 컨테이너 추가
],
),
)
);
}
// 컨테이터 위젯 구현
Widget titleSection = Container(
// 컨테이너 내부 상하좌우에 32픽셀만큼의 패딩 삽입
padding: const EdgeInsets.all(32),
// 자식으로 로우를 추가
child: Row(
// 로우에 위젯들(Expanded, Icon, Text)을 자식들로 추가
children: <Widget>[
// 첫번째 자식
Expanded(
// 첫번째 자식의 자식으로 컬럼 추가
child: Column(
crossAxisAlignment: CrossAxisAlignment.start, // 자식들을 왼쪽정렬로 배치함
// 컬럼의 자식들로 컨테이너와 텍스트를 추가
children: <Widget>[
// 컬럼의 첫번째 자식 컨테이너
Container(
padding: const EdgeInsets.only(bottom: 8), // 컨테이너 내부 하단에 8픽셀만큼 패딩 삽입
child: Text( // 컨테이너의 자식으로 텍스트 삽입
"Oeschinen Lake Campground",
style: TextStyle(
fontWeight: FontWeight.bold // 텍스트 강조 설정
),
),
),
// 컬럼의 두번째 자식으로 텍스트 삽입
Text(
'Kandersteg, Switzerland',
style: TextStyle(
color: Colors.grey[500] // 텍스트의 색상을 설정
),
)
],
),
),
// 두번째 자식 아이콘
Icon(
Icons.star, // 별모양 아이콘 삽입
color: Colors.red[500], // 빨간색으로 설정
),
// 세번째 자식
Text('43') // 텍스트 표시
],
),
);
}
우선 Scaffold 위젯 body 항목을 Center 위젯에서 Column 위젯으로 변경하였다. 컬럼 위젯을 이용하면 수직으로 여러 위젯을 배열할 수 있게된다. 현재 코드에는 titleSection 위젯만을 자식들로 추가한 상태이다.
titleSection 위젯을 구현내용을 살펴보면 컨테이너 위젯을 구현하고 있다. 이 컨테이너는 로우를 자식으로 가지며, 로우는 다시 Expanded와 Icon 그리고 Text 위젯을 자식들로 가진다. 이 세 위젯들은 로우에 등록되어 수평적으로 출력되게 된다.
첫번째 자식인 Expanded는 컬럼을 자식으로 할당하므로 컬럼에 추가될 자식들은 수직적으로 추가될 것이다.
컴럼을 crossAxisAlignment: CrossAxisAlignment.start 로 설정하면 자식 위젯들이 왼쪽정렬로 추가된다.
컬럼의 첫번째 자식은 컨테이너이며 내부 하단에 8픽셀의 패딩값을 가지는 Text로 구성된다. 컬럼의 두번째 자식은 텍스트이며 글자색이 회색으로 설정된다.
위 코드의 실행화면은 다음과 같다.
3 단계 - 버튼 로우 구현
소스코드를 다음과 같이 수정한다.
import 'package:flutter/material.dart';
// MyApp을 시작 위젯으로 설정하여 앱을 실행
void main() => runApp(MyApp());
// 앱의 시작점에 해당하는 위젯
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 본 앱의 테마의 대표색상을 필드에 저장
Color color = Theme.of(context).primaryColor;
// 버튼 로우 구성을 위한 컨테이너 위젯
Widget buttonSection = Container(
child: Row( // 로우를 자식으로 가짐
mainAxisAlignment: MainAxisAlignment.spaceEvenly, // 자식들이 여유 공간을 공편하게 나눠가짐
children: <Widget>[ // 세개의 위젯들을 자식들로 가짐
_buildButtonColumn(color, Icons.call, 'CALL'),
_buildButtonColumn(color, Icons.near_me, 'ROUTH'),
_buildButtonColumn(color, Icons.share, 'SHARE')
],
),
);
// 매트리얼앱을 생성하여 반환
return MaterialApp(
title: 'Flutter Layout Demo', // 앱의 타이틀
theme: ThemeData( // 앱의 테마 설정
primarySwatch: Colors.red, // 주요 테마 색상
),
// 홈 설정. 홈은 메트리얼앱의 시작점
home:Scaffold(
appBar: AppBar(
title: Text("Flutter layout demo"),
),
// 기존 body 삭제
// body: Center(
// child: Text("Hello World"),
// ),
// 새로운 body 선언
body: Column( // 컬럼으로 교체
// 자식들을 추가
children: <Widget>[
titleSection, // titleSection 컨테이너 추가
buttonSection, // buttonSection 컨테이너 추가
],
),
)
);
}
// 타이틀 로우 구성을 위한 컨테이터 위젯 구현
Widget titleSection = Container(...);
// 버튼과 텍스트로 구성된 컬럼을 생성하여 반환하는 함수
Column _buildButtonColumn(Color color,IconData icon, String label){
// 컬럼을 생성하여 반환
return Column(
mainAxisSize: MainAxisSize.min, // 여유공간을 최소로 할당
mainAxisAlignment: MainAxisAlignment.center, // 가운데 정렬
// 컬럼의 자식들로 아이콘과 컨테이너를 등록
children: <Widget>[
Icon(
icon,
color: color,
),
Container(
margin: const EdgeInsets.only(top: 8), // 컨테이너 상단에 8픽셀의 마진을 할당
child: Text( // 텍스트 할당
label,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w400,
color: color
),
),
)
],
);
}
}
우선 build 함수 내부에 color 필드가 추가되었으며 본 앱의 테마의 대표색상을 저장하고 있다.
다음으로 MaterialApp 함수 내부의 body 항목에 새로운 자식으로 buttonSection이 추가되었다. 이로써 titleSection 하단에 buttonSection이 출력될 것이다.
buttonSection 위젯은 컨테이너 위젯으로 로우를 자식으로 가지며 mainAxisAlignment: MainAxisAlignment.spaceEvenly 로 설정되어 추가되는 자식들은 여유공간을 동일하게 나눠가지게 된다. 자식들은 _buildButtonColum 함수 호출을 통해 로우에 추가되는 형태이다. _buildButtonColum 함수 호출시 build 함수 호출시 필드에 저장한 color 값과, 생성할 Icon의 데이터, 그리고 텍스트 값을 파라미터로 전달하게 된다.
_buildButtonColum 함수는 Color과 IconData, String 타입의 아규먼트를 받아 컬럼을 생성하여 반환하는 함수이다. 반환되는 컬럼은 아이콘과 텍스트를 포함하는 컨테이너로 구성되어 반환된다.
위 코드의 실행화면은 다음과 같다.
앞서 구현한 titleSection 밑에 buttonSection이 추가된 것을 확인할 수 있다.
4 단계 - 텍스트 영역 구현
소스코드를 다음과 같이 수정한다.
import 'package:flutter/material.dart';
// MyApp을 시작 위젯으로 설정하여 앱을 실행
void main() => runApp(MyApp());
// 앱의 시작점에 해당하는 위젯
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 본 앱의 테마의 대표색상을 필드에 저장
Color color = Theme.of(context).primaryColor;
// 버튼 로우 구성을 위한 컨테이너 위젯
Widget buttonSection = Container(...);
// 매트리얼앱을 생성하여 반환
return MaterialApp(
title: 'Flutter Layout Demo', // 앱의 타이틀
theme: ThemeData( // 앱의 테마 설정
primarySwatch: Colors.red, // 주요 테마 색상
),
// 홈 설정. 홈은 메트리얼앱의 시작점
home:Scaffold(
appBar: AppBar(
title: Text("Flutter layout demo"),
),
// 기존 body 삭제
// body: Center(
// child: Text("Hello World"),
// ),
// 새로운 body 선언
body: Column( // 컬럼으로 교체
// 자식들을 추가
children: <Widget>[
titleSection, // titleSection 컨테이너 추가
buttonSection, // buttonSection 컨테이너 추가
textSection // textSection 컨테이너 추가
],
),
)
);
}
// 타이틀 로우 구성을 위한 컨테이터 위젯 구현
Widget titleSection = Container(...);
// 버튼과 텍스트로 구성된 컬럼을 생성하여 반환하는 함수
Column _buildButtonColumn(Color color,IconData icon, String label){...}
// 텍스트로 구성된 컨테이너를 구현하는 위젯
Widget textSection = Container(
padding: const EdgeInsets.all(32),
child: 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, // 텍스트가 영역을 넘어갈 경우 줄바꿈 여부
),
);
}
MaterialApp 함수내부의 body 부분에 textSection을 추가한다.
textSection 위젯은 텍스트를 자식으로 가지는 컨테이너다. 텍스트는 길 문장으로 이루어져있는데 softWrap 항목이 true로 설정되어 있다. softWrap 항목은 텍스트가 해당 영역을 넘어갈 경우 줄바꿈을 할지 여부를 설정할 수 있다.
상기 코드의 실행화면은 다음과 같다.
5 단계 - 이미지 영역 구현
이번 단계를 위해서는 우선 이미지를 프로젝트에 추가해야 한다. 사용한 이미지는 아래의 링크에서 다운로드 가능하다. 프로젝트의 루트 위치에 images라는 디렉토리를 만든 후 다운로드한 이미지를 해당 폴더로 복사한다.
복사한 이미지를 앱의 자원으로 등록하기 위해서 pubspec.yaml 파일을 다음과 같이 수정한다.
# The following section is specific to Flutter.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
assets:
- images/lake.jpg
# - images/a_dot_ham.jpeg
위와 같이 수정한 후 yaml 파일을 저장하고 에러 메시지가 출력되지 않는다면 정상적으로 추가된 것이다.
다음과 같이 소스 코드를 수정한다.
import 'package:flutter/material.dart';
// MyApp을 시작 위젯으로 설정하여 앱을 실행
void main() => runApp(MyApp());
// 앱의 시작점에 해당하는 위젯
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 본 앱의 테마의 대표색상을 필드에 저장
Color color = Theme.of(context).primaryColor;
// 버튼 로우 구성을 위한 컨테이너 위젯
Widget buttonSection = Container(...);
// 매트리얼앱을 생성하여 반환
return MaterialApp(
title: 'Flutter Layout Demo', // 앱의 타이틀
theme: ThemeData( // 앱의 테마 설정
primarySwatch: Colors.red, // 주요 테마 색상
),
// 홈 설정. 홈은 메트리얼앱의 시작점
home:Scaffold(
appBar: AppBar(
title: Text("Flutter layout demo"),
),
// 기존 body 삭제
// body: Center(
// child: Text("Hello World"),
// ),
// 새로운 body 선언
body: Column( // 컬럼으로 교체
// 자식들을 추가
children: <Widget>[
// 이미지 추가
Image.asset(
'images/lake.jpg',
width: 600,
height: 240,
fit: BoxFit.cover,
),
titleSection, // titleSection 컨테이너 추가
buttonSection, // buttonSection 컨테이너 추가
textSection // textSection 컨테이너 추가
],
),
)
);
}
// 타이틀 로우 구성을 위한 컨테이터 위젯 구현
Widget titleSection = Container(...);
// 버튼과 텍스트로 구성된 컬럼을 생성하여 반환하는 함수
Column _buildButtonColumn(Color color,IconData icon, String label){...}
// 텍스트로 구성된 컨테이너를 구현하는 위젯
Widget textSection = Container(...);
}
MaterialApp의 body 컬럼에 첫번째 자식으로 Image를 추가하고 있다. fit 항목에서 이미지를 어떻게 출력할지 설정할 수 있으며 cover로 설정되면 이미지를 가능한 작게하여 할당된 영역을 채우게 된다. cover를 포함한 다른 설정 방식은 Flutter BoxFit 레퍼런스를 참고한다.
상기 소스코드의 실행 화면은 다음과 같다.
6 단계 - 마지막 손질
다음 소스 코드와 같이 body 항목을 컬럼에서 리스트뷰로 변경하였다. 이는 일부 화면의 크기가 작은 장비에서도 등록한 자식들이 스크롤되면서 정상 출력되도록 하기 위함이다.
// 앱의 시작점에 해당하는 위젯
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 본 앱의 테마의 대표색상을 필드에 저장
Color color = Theme.of(context).primaryColor;
// 버튼 로우 구성을 위한 컨테이너 위젯
Widget buttonSection = Container(...);
// 매트리얼앱을 생성하여 반환
return MaterialApp(
title: 'Flutter Layout Demo', // 앱의 타이틀
theme: ThemeData( // 앱의 테마 설정
primarySwatch: Colors.red, // 주요 테마 색상
),
// 홈 설정. 홈은 메트리얼앱의 시작점
home:Scaffold(
appBar: AppBar(
title: Text("Flutter layout demo"),
),
// 기존 body 삭제
// body: Center(
// child: Text("Hello World"),
// ),
// 새로운 body 선언
// body: Column( // 컬럼으로 교체
body: ListView( // 리스트뷰로 교체
// 자식들을 추가
children: <Widget>[
// 이미지 추가
Image.asset(
'images/lake.jpg',
width: 600,
height: 240,
fit: BoxFit.cover,
),
titleSection, // titleSection 컨테이너 추가
buttonSection, // buttonSection 컨테이너 추가
textSection // textSection 컨테이너 추가
],
),
)
);
}
Flutter Code Examples 강좌를 추천합니다.
- 제 블로그에서 Flutter Code Examples 프로젝트를 시작합니다.
- Flutter의 다양한 예제를 소스코드와 실행화면으로 제공합니다.
- 또한 모든 예제는 Flutter Code Examples 앱을 통해 테스트 가능합니다.
Flutter Code Examples 강좌로 메뉴로 이동
'Development > Flutter' 카테고리의 다른 글
Flutter 강좌 - Screen Naviation | 화면(라우트)간 이동 (3) | 2019.06.24 |
---|---|
Flutter 강좌 - Statefull widget | 상호작용 기능 (4) | 2019.06.24 |
Flutter 강좌 - Using Material Components | Scaffold 컴포넌트 사용법 (2) | 2019.06.10 |
Flutter 강좌 - Basic widgets | 기본 위젯 (4) | 2019.06.10 |
Flutter 강좌 - Hello World 만들기 (2) | 2019.06.04 |