Flutter 기본 위젯
플러터는 화면에 그려지는 모든 요소가 위젯으로 구성되어 있다 플러터는 기본적으로 위젯을 제공하고 직접 위젯을 만들수 있다
자식을 하나만 가지는 위젯
- Container 위젯: 자식을 담는 컨테이너의 역할 자식을 담고 배경색, 너비와 높이, 테두리 디자인등을 설정할 수 있다
- GestureDetector 위젯: 플러터에서 제공하는 제스처 기능을 자식 위젯에서 인식하는 위젯
- SizedBox 위젯: 높이와 너비를 지정하는 위젯 Container와 다르게 디작인 적인 요소를 적용할 수 없고 const 생성자로 선언이 가능하다
위 위젯들은 대체로 child 매개변수를 입력받는다
다수의 자식을 가지는 위젯
- Column 위젯: children 매개변수에 입력된 모든 위젯들을 세로로 배치
- Row 위젯: children 매개변수에 입력된 모든 위젯들을 가로로 배치
- ListView 위젯: 리스트를 구현할 때 사용, 입력된 위젯이 화면을 벗어나게 된다면 스크롤이 가능
위 위젯들은 대체로 children 매개변수를 입력받는다
위젯 트리
위 UI의 위젯 트리
코드
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center( // 화면 중앙에 배치
child: Row(
mainAxisAlignment: MainAxisAlignment.center, // Row의 자식들을 중앙에 정렬
crossAxisAlignment: CrossAxisAlignment.center, // 세로 축에서 중앙 정렬
children: [
Container(
color: Colors.yellow, // 노란색 배경 추가
width: 100, // 너비 설정
height: 100, // 높이 설정
),
SizedBox(width: 16), // 노란색 Container와 아이콘 그룹 사이 간격 추가
Row(
mainAxisSize: MainAxisSize.min, // Row의 크기를 자식 위젯 크기로 제한
children: [
Column(
mainAxisSize: MainAxisSize.min, // Column의 크기를 자식 위젯 크기로 제한
children: [
Icon(Icons.skip_next),
Text("앞으로"),
],
),
SizedBox(width: 16), // 간격 추가
Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.skip_previous),
Text("뒤로"),
],
),
SizedBox(width: 16), // 간격 추가
Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.home),
Text("홈"),
],
),
],
),
],
),
),
),
);
}
}
위젯의 형태
위젯의 형태는 2가지로 나뉜다
- StateFul: 위젯의 내부에서 값이 변경되었을 때 위젯 자체에서 다시 렌더링을 실행
- StateLess: 위젯과 위젯 내부에서 값이 변경되어도 위젯 자체적으로 다시 렌더링할 수 없음
텍스트 위젯
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
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
int number = 123;
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.black, // 배경색 설정
body: Center(
child: Text(
"Hello world! ${number}",
style: TextStyle(
fontSize: 15.0,
fontWeight: FontWeight.w700,
color: Colors.yellow, // 텍스트 색상을 노란색으로 설정
),
),
),
),
);
}
}
Text를 이용해서 텍스트를 표시하고 style의 TextStyle을 이용해서 폰트, 크기, 색상을 변경할 수 있다
또한 Text위젯에서 변수값을 출력할려면 ""안에 ${변수명}을 이용해서 변수를 출력할 수 있다
제스처 위젯
사용자가 키보드로 입력하거나 화면을 터치하는등 모든 입력을 플러터에서는 제스처라고 부른다 GestureDetector 위젯은 모든 제스처를 매개변수로 제공해준다
1.Button 위젯
기본 패키지에서 제공하는 버튼으로는 TextButton, OutlinedButton, ElevatedButton이 존재한다 이 3개는 모두 버튼을 누르면 색이 변경되는 리플 효과를 지원한다
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
38
39
40
41
42
43
44
45
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.black, // 배경색 설정
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center, // 버튼들을 중앙 정렬
children: [
TextButton(
onPressed: () {}, // 클릭 시 실행
style: TextButton.styleFrom(
foregroundColor: Colors.red, // 버튼 텍스트 색상 지정
),
child: Text("TextButton"),
),
OutlinedButton(
onPressed: () {}, // 클릭 시 실행
style: OutlinedButton.styleFrom(
foregroundColor: Colors.red, // 버튼 텍스트 색상 지정
),
child: Text("OutlinedButton"),
),
ElevatedButton(
onPressed: () {}, // 클릭 시 실행
style: ElevatedButton.styleFrom(
foregroundColor: Colors.red, // 버튼 텍스트 색상 지정
),
child: Text("ElevatedButton"),
),
],
),
),
),
);
}
}
- TextButton: 텍스트만 있는 버튼
- OutlinedButton: 테두리가 있는 버튼
- ElevatedButton: 입체적으로 튀어나온 느낌의 배경이 들어간 버튼
2. IconButton 위젯
아이콘을 버튼으로 하는 위젯이다 icon 매개변수에 보여주고 싶은 아이콘을 넣을 수 있다
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
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
//backgroundColor: Colors.black, // 배경색 설정
body: Center(
child: IconButton(
onPressed: (){},
icon: Icon(
Icons.home,
),
),
),
),
);
}
}
3. GestureDetector 위젯
손가락으로 하는 여러가지 입력을 인지하는 위젯이다
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
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
//backgroundColor: Colors.black, // 배경색 설정
body: Center(
child: GestureDetector(
onTap: (){
print("tap");
},
onDoubleTap: (){
print("double tap");
},
onLongPress: (){
print("long press");
},
)
),
),
);
}
}
화면을 터치했을때 터미널에 결과가 출력된다
| 매개변수 | 설명 |
|---|---|
| onPanStart | 수평 또는 수직으로 드래그가 시작됐을 때 실행하는 함수 |
| onPanUpdate | 수평 또는 수직으로 드래그를 하는 동안 위치가 업데이트될 때마다 실행되는 함수 |
| onPanEnd | 수평 또는 수직으로 드래그가 끝났을 때 실행하는 함수 |
| onHorizontalDragStart | 수평으로 드래그가 시작됐을 때 실행하는 함수 |
| onHorizontalDragUpdate | 수평으로 드래그를 하는 동안 위치가 업데이트될 때마다 실행되는 함수 |
| onHorizontalDragEnd | 수평으로 드래그가 끝났을 때 실행하는 함수 |
| onVerticalDragStart | 수직으로 드래그가 시작됐을 때 실행하는 함수 |
| onVerticalDragUpdate | 수직으로 드래그를 하는 동안 위치가 업데이트될 때마다 실행되는 함수 |
| onVerticalDragEnd | 수직으로 드래그가 끝났을 때 실행하는 함수 |
| onScaleStart | 확대가 시작됐을 때 실행되는 함수 |
| onScaleUpdate | 확대가 진행되는 동안 확대가 업데이트될 때 실행되는 함수 |
| onScaleEnd | 확대가 끝났을 때 실행되는 함수 |
4. FloatingActionButton 위젯
안드로이드를 사용하다보면 공중에 떠있는 버튼을 볼 수 있다 이들은 FloatingActionButton으로 간단하게 구현할 수 있다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
//backgroundColor: Colors.black, // 배경색 설정
body: Center(
child: FloatingActionButton(
onPressed: (){},
child:Text("클릭"),
),
),
),
);
}
}
디자인 위젯
배경이난 간격, 패딩을 추가하는 등 디자인적인 요소를 적용할 때 사용한다
1. Container 위젯
다른 위젯을 담는 데 사용된다 위젯의 너비와 높이를 지정하거나, 배경이나 테두리를 추가할 때 주로 사용한다
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
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Container(
decoration: BoxDecoration(
color: Colors.red, // 컨테이너 내부 배경색
border: Border.all(
width: 3.0, //테두리 두께
color: Colors.yellow, //테두리 색상
),
borderRadius: BorderRadius.circular( //테두리 굴곡
15.0,
),
),
height: 200.0, //세로
width: 100.0, //가로
child: Text("container"),
),
),
),
);
}
}
2. SizedBox 위젯
일정 크기의 공간을 공백으로 두고 싶을 때 사용한다 Container를 사용해도 공백을 만들수 있지만 SizedBox는 const 생성자를 사용했을 때 좀더 효율이 좋다
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
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
//backgroundColor: Colors.black, // 배경색 설정
body: Center(
child: SizedBox(
height: 200.0, //세로
width: 200.0, //가로
child: Container(
color: Colors.amber,
)
),
),
),
);
}
}
SizedBox는 색상이 없기 때문에 Container를 만들어서 크기를 보여준다
3. Padding 위젯
child 위젯에 여백을 제공할 때 사용한다 패딩 위젯을 사용하면 상위 위젯과 하위 위젯 사이의 여백을 둘 수 있다 매개변수로 EdgeInsets 값을 입력해야한다
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
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Container(
color:Colors.red,
child: Padding(
padding: EdgeInsets.all(
16.0
),
child: Container(
color: Colors.teal,
width: 100.0,
height: 100.0,
),
),
),
),
),
);
}
}
또한 위젯 바깥에 간격을 추가해주는 margin이라는 기능도 있다(플러터에서 자주 사용하지 않음) 따로 위젯이 존재하지 않고 Container위젯에 추가한다
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
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Container( // margin이 적용되는 대상 1 컨테이너
color:Colors.red,
child: Container( // 2 컨테이너
color: Colors.blue,
margin: EdgeInsets.all(
32.0
),
child: Padding(
padding: EdgeInsets.all(
16.0
),
child: Container( // 3 컨테이너
color: Colors.teal,
width: 100.0,
height: 100.0,
),
),
),
),
),
),
);
}
}
4. SafeArea
SafeArea는 기기별로 다른 화면 (예 아이폰 노치, 아일랜드) 때문에 위젯이 가려질 수 있다 SafeArea를 이용하면 기기별로 예외처리하지 않고 안전한 화면에서만 위젯을 넣을 수 있다
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
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Align(
alignment: Alignment.topLeft, // 원하는 위치 (예: 왼쪽 상단)
child: SafeArea(
top: true, // false 변경하면 화면 위쪽을 채울 수 있다
bottom: true,
left: true,
right: true,
child: Container(
color: Colors.amber,
width: 300.0,
height: 300.0,
)
),
),
),
);
}
}
배치 위젯
하위 위젯을 가로 또는 세로로 배치하거나 위젯 위에 위젯을 겹칠 때 사용한다
1. Row 위젯
Row는 Column과 함께 위젯을 가로 세로로 배치하는데 사용한다 Row는 가로로 배치할 때 사용한다 하나의 child를 받지않고 여러개 위젯을 받을수 있는 children: [ ] 을 이용한다 이때 각각의 주축과 반대축이 존재하고 각각 정렬을 지정할 수 있다
Row일때 주축은 세로 반대축은 가로이고 Column인 경우 주축은 가로 반대축은 세로이다
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
38
39
40
41
42
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SizedBox(
height: double.infinity, //높이를 최대한으로 설정
child: Row(
mainAxisAlignment: MainAxisAlignment.start, // 주축 정렬 지정
crossAxisAlignment: CrossAxisAlignment.center, // 반대축 정렬 지정
children: [
Container(
height: 50,
width: 50,
color: Colors.red,
),
SizedBox(width: 15,),
Container(
height: 50,
width: 50,
color: Colors.amber,
),
SizedBox(width: 15,),
Container(
height: 50,
width: 50,
color: Colors.blue,
),
],
),
),
),
);
}
}
위 코드에서 mainAxisAlignment: MainAxisAlignment.center로 수정후 결과
중앙에 표시된다
mainAxisAlignment: MainAxisAlignment.end의 결과
mainAxisAlignment: MainAxisAlignment.spaceBetween의 결과
간격 사이를 균등하게 조절한다
mainAxisAlignment: MainAxisAlignment.spaceAround의 결과
자식 위젯 간격을 균등하게 배정하고 왼쪽끝과 오른쪽 끝을 위젯 사이 거리의 반만큼 배정한다 위 결과는 SizedBox가 적용된 결과라 완전히 절반이 아님
mainAxisAlignment: MainAxisAlignment.spaceEvenly의 결과
자식 위젯 간격을 균등하게 배치하고 양쪽 끝도 같은 간격을 배치 여기서는 SizedBox를 제거해서 정확히 간격이 같음
위 코드에서 주축 정렬을 바꿔봤는데 반대축의 정렬도 바꿀 수 있다
주축은 center 반대축 정렬만 수정 SizedBox 없음
crossAxisAlignment: CrossAxisAlignment.start의 결과
SafeAera를 설정하지 않아서 겹치게 표시되었다
crossAxisAlignment: CrossAxisAlignment.end의 결과
crossAxisAlignment: CrossAxisAlignment.stretch 의 결과
반대 축 최대한 늘려서 정렬
2. Column 위젯
Row와 비슷하지만 주축과 반대축이 완전히 반대로 이루어져 있다
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
38
39
40
41
42
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SizedBox(
width: double.infinity, //높이를 최대한으로 설정
child: Column(
mainAxisAlignment: MainAxisAlignment.start, // 주축 정렬 지정
crossAxisAlignment: CrossAxisAlignment.center, // 반대축 정렬 지정
children: [
Container(
height: 50,
width: 50,
color: Colors.red,
),
//SizedBox(width: 15,),
Container(
height: 50,
width: 50,
color: Colors.amber,
),
//SizedBox(width: 15,),
Container(
height: 50,
width: 50,
color: Colors.blue,
),
],
),
),
),
);
}
}
mainAxisAlignment: MainAxisAlignment.end 의 결과
mainAxisAlignment: MainAxisAlignment.spaceBetween 의 결과
이전과 동일하게 자식간의 가격을 동일한 크기로 배치한다
다른 정렬도 Row와 기능은 같지만 배치가 세로인것만 차이가 난다
3. Flexible 위젯
Row나 Column에서 사용하는 위젯으로 Flexible위젯을 Column과 Row에서 사용하면 Flexible에 제공된 child가 크기를 최소한으로 차지하게 할 수 있다 flex매개변수를 이용해서 각 Flexible위젯이 얼만큼의 비율로 공간을 차지할지 지정할 수 있다 또한 매개변수 fit의 값 FlexFit.tight를 사용해서 남은 공간을 모두 차지하거나 FlexFit.loose를 이용하면 위젯이 필요한 공간만 차지한다
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
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SizedBox(
width: double.infinity, //높이를 최대한으로 설정
child: Column(
children: [
Flexible(
flex: 1,
child: Container(
color: Colors.red,
),
),
Flexible(
flex: 1,
child: Container(
color: Colors.purple,
),
)
],
),
),
),
);
}
}
4. Expanded 위젯
Expanded 위젯은 Flexible 위젯을 상속하는 위젯이다 Column과 Row에서 Expanded를 사용하면 윚세이 남아 있는 공간을 최대한으로 차지한다 Expanded는 Flexible의 fix 매개변수에 FlexFit.tight를 넣은 위젯이다
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
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SizedBox(
width: double.infinity, //높이를 최대한으로 설정
child: Column(
children: [
Expanded(
child: Container(
color: Colors.red,
),
),
Expanded(
child: Container(
color: Colors.purple,
),
)
],
),
),
),
);
}
}
5. Stack 위젯
Stack위젯은 위젯을 겹치는 기능을 제공한다
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
38
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SizedBox(
width: double.infinity, //높이를 최대한으로 설정
child: Stack(
children: [
Container(
height: 300,
width: 300,
color: Colors.red
),
Container(
width: 200,
height: 200,
color: Colors.amber
),
Container(
width: 100,
height: 100,
color: Colors.black
)
],
),
),
),
);
}
}
Stack 내부에서 먼저 작성한 것이 제일 아래에 생성되고 마지막에 생성한 위젯이 제일 위에서 생성된다