Flutter 기초
Flutter
Flutter 학습 중 중요한 부분들을 정리 해놓으려고 합니다.
AppBar 의 shadow
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 값을 주면 배경색이 유지된 채로 그림자 효과를 줄 수 있습니다.
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 속성을 설정해주면 해결 됩니다.