Post

Flutter 기본 위젯

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,
            ) 
          ),
        ),
      ),
    );
  }
}
top true
top false

 

배치 위젯

하위 위젯을 가로 또는 세로로 배치하거나 위젯 위에 위젯을 겹칠 때 사용한다

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,
                ),
              )
            ],
          ),
        ),
      ),
    );
  }
}
1:11:3

 

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 내부에서 먼저 작성한 것이 제일 아래에 생성되고 마지막에 생성한 위젯이 제일 위에서 생성된다

This post is licensed under CC BY 4.0 by the author.