Post

Flutter 기초

Flutter

Flutter 학습 중 중요한 부분들을 정리 해놓으려고 합니다.

AppBar 의 shadow

image

Flutter AppBar widget 에서 elevation 값을 변경할 때 배경색도 함께 어두워지는 현상이 나타났습니다.

1
2
3
4
5
6
7
8
9
10
11
@override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(
        elevation: 2,
        surfaceTintColor: Colors.white,
        backgroundColor: Colors.white,
        foregroundColor: Colors.green.shade500,
        shadowColor: Colors.black,
        ...

다음과 같이 surfaceTintColor 값을 설정해둔 다음 elevation 값을 주면 배경색이 유지된 채로 그림자 효과를 줄 수 있습니다.

image

Initializer lists

dart 에는 신기한 문법이 존재합니다. 바로 Initializer lists 인데요. 코드와 함께 살펴보도록 하겠습니다

1
2
3
4
5
6
7
class WebtoonModel {
  final String title, thumb, id;
  WebtoonModel.fromJson(Map<String, dynamic> json)
      : title = json['title'],
        thumb = json['thumb'],
        id = json['id'];
}

이 문법을 사용하면 json 데이터로부터 데이터를 받아와 해당 데이터로 초기화 된 객체를 생성할 수 있습니다.

FutureBuilder

flutter 에는 FutureBuilder 라고 하는 아주 좋은 위젯이 있습니다.

이전에 전공 수업에서 팀 프로젝트를 할 때 initState(), setState() 를 이용 하면서 굉장히 골치 아팠던 기억이 있는데, FutureBuilder 를 사용하면 stateful widget 이 아닌 stateless widget 을 이용하여 훨씬 더 간편하게 API 로부터 데이터를 받아올 수 있습니다.

1
final Future<List<WebtoonModel>> webtoons = ApiService.getTodaysToons();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
body: FutureBuilder(
        future: webtoons,
        builder: (context, futureResult) {
          if (futureResult.hasData) {
            return Column(
              children: [
                const SizedBox(
                  height: 100,
                ),
                Expanded(child: webtoonListView(futureResult))
              ],
            );
          }
          return const Center(
            child: CircularProgressIndicator(),
          );
        },
      ),

다음과 같은 future 타입 List 가 있을 때, FutureBuilder 에 넣어주면 futureResult(변수 명은 사용자가 변경 가능) 이라는 변수를 생성합니다. 이 변수는 아래에서 서술할 ListView 에서 사용할 수 있습니다.

만약 아직 await 상태일 때는 로딩 창이 뜨도록(CircularProgressIndicator()) 설정 해두었습니다. 이렇게 하면 로딩 -> 데이터 get -> 화면에 출력 순으로 자연스럽게 이어집니다.

ListView.builder

위의 futureBuilder 로부터 받아온 API 의 데이터가 List 일 때, LIstView.builder 는 아주 유용하게 사용됩니다.

1
2
3
4
5
6
7
8
9
10
ListView webtoonListView(AsyncSnapshot<List<WebtoonModel>> futuerResult) {
    return ListView.builder(
      scrollDirection: Axis.horizontal,
      itemCount: futuerResult.data!.length,
      itemBuilder: (context, index) {
        var webtoon = futuerResult.data![index];
        return Text(webtoon.title);
      },
    );
  }

FutureBuilder 가 생성해준 futureResult 변수를 전달받고, itenCount 와 itemBuilder 를 통해 화면에 출력할 데이터의 범위를 정할 수 있습니다.

ListView.builder 의 좋은 점은 데이터를 전부 출력하는 것이 아닌 화면에 보이는 변수만 load 하기 때문에 훨씬 효율적입니다.

1
2
3
4
5
6
7
8
9
10
11
ListView webtoonListView(AsyncSnapshot<List<WebtoonModel>> futureResult) {
    return ListView.separated(
      scrollDirection: Axis.horizontal,
      itemCount: futureResult.data!.length,
      itemBuilder: (context, index) {
        var webtoon = futureResult.data![index];
        return Text(webtoon.title);
      },
      separatorBuilder: (context, index) => const Text("🩵"),
    );
  }

또한 ListView.separated 를 사용하면 List 원소 사이에 다른 요소를 삽입할 수도 있습니다.

Expanded

1
2
3
4
**error**
RenderBox was not laid out: RenderViewport#519f8 NEEDS-PAINT
'package:flutter/src/rendering/box.dart':
Failed assertion: line 2164 pos 12: 'hasSize'

Column 등의 위젯을 사용할 때 ListView 위젯을 그대로 사용하면 오류가 발생합니다. ListView 위젯의 높이를 알 수 없기 때문에 발생하는 오류인데, 이는 Expanded 위젯을 사용하여 해결할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
body: FutureBuilder(
        future: webtoons,
        builder: (context, futureResult) {
          if (futureResult.hasData) {
            return Column(
              children: [
                const SizedBox(
                  height: 100,
                ),
                Expanded(child: webtoonListView(futureResult))
              ],
            );
          }
          return const Center(
            child: CircularProgressIndicator(),
          );
        },
      )

Expanded 는 화면의 남는 공간을 차지하는 위젯입니다. 따라서 ListView 타입의 변수 또는 ListView 를 리턴 하는 메소드를 Expanded 위젯으로 감싸주면 해결됩니다.

clipBehavior

flutter 에서 디자인을 변경하려고 할 때 적용이 안되는 경우가 있습니다.

1
2
3
4
Container(
              width: 400,
              clipBehavior: Clip.hardEdge,
              ...

다음과 같이 clipBehavior 속성을 설정해주면 해결 됩니다.

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