Fetch data from the internet
1.http 패키지 추가
flutter pub add http
- http를 사용하여 GET/POST의 방식으로 서버 API를 호출할 수 있다.
2.네트워크 요청 생성
- 메서드를 사용해서 JSONPlaceholder에서 샘플 앨범을 가져올 수 있다.
Future<http.Response> fetchAlbum() {
return http.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1'));
}
- Future()
: Future 클래스의 인스턴스이다. future은 비동기 작업의 결과를 나타내며 미완료, 완료 중 한 가지 상태를 가진다. 미완료 시, 비동기 함수를 호출하면 미완료 된 future을 반환한다. 해당 future은 함수의 비동기 작업이 끝나거나 에러 발생을 기다린다. 완료 시, 비동기 작업이 성공적으로 끝나면 future은 완료되고 그렇지 않으면 에러로 완료된다.
- Uri()
: Uri 클래스는 URL에서 사용할 문자열을 인코딩하고 디코딩하는 함수를 제공한다. 이러한 함수는 URI에 특수한 문자를 처리한다. (& 혹은 =)
- parse()
: parse는 프로그램을 분석하고 런타임 환경이 실제로 실행할 수 있는 내부 형식으로 변환하는 것을 의미한다. 이 곳에서는 Json의 데이터를 텍스트 그대로 가져오는 것이 아니라 분석하고 사용 형식에 맞춰 변경해 사용할 수 있도록 하기 위해 사용했다.
3.응답을 Dart 객체로 변환
- 효율성 있는 원시 작업을 위해 http.Response의 값을 Dart 객체로 변환하는 과정이 필요하다.
class Album {
final int userId;
final int id;
final String title;
const Album({
required this.userId,
required this.id,
required this.title,
});
factory Album.fromJson(Map<String, dynamic> json) {
return switch (json) {
{
'userId': int userId,
'id': int id,
'title': String title,
} =>
Album(
userId: userId,
id: id,
title: title,
),
_ => throw const FormatException('Failed to load album.'),
};
}
}
- namedConstructor
: namedConstructor은 클래스에 대해 여러 생성자를 구현하거나 추가 명확성을 제공하기 위해 사용한다. 이름 있는 생성자를 선언하면 기본 생성자는 생략할 수 없다.
- Map()
: Map()은 연관된 키를 사용하여 검색하는 키/값 쌍의 컬렉션이다. 맵에는 유한한 수의 키가 있으며 각 키에는 정확히 하나의 값이 연결되어 있다. 맵과 해당 키 및 값은 반복될 수 있으며, 반복 순서는 개별 지도 유형에 따라 정의된다.
4.데이터 Fetch
class _MyAppState extends State<MyApp> {
late Future<Album> futureAlbum;
@override
void initState() {
super.initState();
futureAlbum = fetchAlbum();
}
// ···
}
- initState()
: initState은 객체가 트리에 삽입될 때 정확히 한 번 호출된다. 이 객체가 트리에 삽입된 위치 또는 이 객체를 구성하는 데 사용된 위젯에 따라 초기화를 수행하기 위해 이 메서드를 재정의한다.
5.데이터 표시
- 화면에 데이터를 표시하기 위해서는 FutureBuilder 위젯을 사용해야 한다. 이 위젯은 비동기 데이터 소스로 쉽게 작업을 할 수 있게 도와준다. 이 때, 두 가지 매개 변수를 함께 제공해야 한다. 바로 ( future, builder )이다. future은 상응하는 함수를 제공해야 하고, build에는 상태에 따라 무엇을 렌더링 할 지 알려야 한다.
FutureBuilder<Album>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!.title);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
// By default, show a loading spinner.
return const CircularProgressIndicator();
},
)
Lists & Grids
Listview
- 목록 작업을 쉽게 해주는 기본 위젯. 가장 일반적으로 사용되는 스크롤 위젯이기도 하다. 스크롤 방향으로 자식을 차례로 표시한다. ListView를 구성하는 데에는 네 가지 옵션이 있다.
1. 기본 생성자는 자식의 명시적인 List<Widget>을 사용한다. 이 생성자는 하위 수가 적은 목록을 보기에 적합하다. 목록을 구성하려면 실제로 표시되는 하위 항목만이 아니라 목록 보기에 표시될 수 있는 모든 하위 항목에 대해 작업을 수행해야 하기 때문이다.
2. ListView.builder 생성자는 요청에 따라 하위 항목을 빌드하는 IndexedWidgetBuilder을 사용한다. 이 생성자는 실제로 표시되는 하위 항목에 대해서만 빌더가 호출되므로 하위 항목 수가 많거나 무한한 목록 보기에 적합하다.
3. ListView.separated 생성자는 두 개의 IndexedWidgetBuilder을 사용한다. 즉, 요청 시 하위 항목을 빌드하고 유사하게 하위 항목 사이에 나타나는 구분 기호 하위를 빌드한다. 이 생성자는 고정된 수의 하위 항목이 있는 목록 보기에 적합하다.
4. ListView.custom 생성자는 하위 모델의 추가 측면을 정의하는 기능을 제공하는 SliverChildDelegate를 사용한다. 예를 들어 실제로 표시되지 않는 어린이의 크기를 추정하는 데 사용되는 알고리즘을 제어할 수 있다.
Horizontal List
- 수직이 아닌 수평으로 스크롤되는 목록을 만들고 싶은 경우, 위젯을 통해 ListView 수평 목록을 만들 수 있다.
ListView(
// This next line does the trick.
scrollDirection: Axis.horizontal,
children: <Widget>[
Container(
width: 160,
color: Colors.red,
),
Container(
width: 160,
color: Colors.blue,
),
Container(
width: 160,
color: Colors.green,
),
Container(
width: 160,
color: Colors.yellow,
),
Container(
width: 160,
color: Colors.orange,
),
],
),
grid view
- GridView 위젯은 경우에 따라 항목을 차례로 표시하는 일반 항목 목록이 아닌 그리드로 항목을 표시하고 싶을 때 사용한다. 그리드 사용을 시작하는 가장 간단한 방법은 생성자를 사용하는 것이다. GridView.count() 를 통해 원하는 행과 열 수를 지정할 수 있다.
GridView.count(
// Create a grid with 2 columns. If you change the scrollDirection to
// horizontal, this produces 2 rows.
crossAxisCount: 2,
// Generate 100 widgets that display their index in the List.
children: List.generate(100, (index) {
return Center(
child: Text(
'Item $index',
style: Theme.of(context).textTheme.headlineSmall,
),
);
}),
),
lists with different types of items
1. 다양한 유형의 항목으로 데이터 소스 만들기
- 목록의 다양한 items의 type을 나타내려면 각 항목 유형에 대한 클래스를 정의해야 한다. 아래는 Dart에서 리스트를 생성하는 예제이다. ListItem이라는 클래스의 객체들을 담은 리스트를 생성한다. 리스트에는 1000개의 항목이 있으며, 각 항목은 HeadingItem 또는 MessageItem의 객체이다. generate 함수를 통하여 1000개의 항목을 생성하고, 조건에 따라 항목이 나눠지도록 처리한다.
final items = List<ListItem>.generate(
1000,
(i) => i % 6 == 0
? HeadingItem('Heading $i')
: MessageItem('Sender $i', 'Message body $i'),
);
2. 데이터 소스를 위젯 목록으로 변환
- ListView.builder() 생성자를 사용한다. 일반적으로 처리 중인 항목 유형을 확인하고 해당 항목 유형에 적합한 위젯을 반환하는 빌더 기능을 제공한다.
ListView.builder(
// Let the ListView know how many items it needs to build.
itemCount: items.length,
// Provide a builder function. This is where the magic happens.
// Convert each item into a widget based on the type of item it is.
itemBuilder: (context, index) {
final item = items[index];
return ListTile(
title: item.buildTitle(context),
subtitle: item.buildSubtitle(context),
);
},
)
lists with spaced items
- 일반적으로 Item 사이의 공간을 넣기 위해 Spacer 또는 Expanded를 사용한다. 그러나 이러한 방법은 유한한 높이 제약이 있기 때문에 스크롤 가능한 위젯 내에서는 불가능하다.
LayoutBuilder은 공간이 충분할 때 List Items를 균등하게 사용하고 ConstrainedBox를 배치한다. 공간이 충분하지 않을 때 사용자가 스크롤할 수 있도록 허용하는 방법을 보여준다.
SinglechildScrollView를 사용하면 상위 컨테이너가 너무 작은 경우에도 하위 위젯을 스크롤할 수 있다.
minHeight/maxHeight을 제약 조건으로 설정하여 사용 가능한 공간, 즉 최대 높이와 동일한 최소 높이를 가지도록 제한한다.
Column 안의 아이템들을 균등하게 유지하려면 mainAxisAlignment에 설정값을 주면된다. spaceBetween은 Column 안의 Items들에게 균등한 간격을 제공한다.
LayoutBuilder(builder: (context, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraints.maxHeight),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ItemWidget(text: 'Item 1'),
ItemWidget(text: 'Item 2'),
ItemWidget(text: 'Item 3'),
],
),
),
);
});
long lists
- ListView는 작은 목록에 적합하다. 많은 수가 포함된 목록을 작업하기 위해서는 ListView.builder 생성자를 사용하는 것이 가장 좋다. ListView.builder은 항목이 화면으로 스크롤 될 때 항목을 생성한다.
ListView.builder(
itemCount: items.length,
prototypeItem: ListTile(
title: Text(items.first),
),
itemBuilder: (context, index) {
return ListTile(
title: Text(items[index]),
);
},
)
참고문서
'Group Study (2023-2024) > Flutter' 카테고리의 다른 글
[Flutter] 6주차 스터디_State management와 Deep linking (1) | 2023.12.23 |
---|---|
[Flutter] 4주차 스터디_StatefulWidget과 BuildContext (0) | 2023.11.27 |
[Flutter] 3주차 스터디_UI Challenge (0) | 2023.11.20 |
[Flutter] 2주차 스터디_Flutter 입문 (0) | 2023.11.13 |
[Flutter] 1주차 스터디_Functional programming 과 Asychronous programming (0) | 2023.11.06 |