27. 플러터 : 서버/클라이언트 연동 (2)

어찌 된게 뭐하나 할 때마다 이렇게 힘이 드는 건지 모르겠다.
얼핏 보면 그냥 되야 하는데
막상 해보면 절대 그냥 되지 않는다.
이 간단한 걸 하는데 서너 시간 이상 들었다.
예전 같지 않은걸까..?

이전 글에서는 사용자 정보를 1개만 가져왔는데
이번에는 전체에 해당하는 10개를 가져와서 리스트뷰에 출력한다.
모든 데이터를 출력하면 지저분해지는 관계로 이름과 이메일만 보여준다.

이전 예제에서 데이터 하나만 보여주기 때문에 단조로운 화면이었다면
이번 예제는 배열을 보여주기 때문에 스크롤 기능을 제공하는 그럴 듯한 앱이라고 부를 수 있겠다.



우재야!
지금까지 했던 것처럼..
이번에도 아래 코드 안보고 위의 그림처럼 만들어 보자.
해보고 잘 안되면 살짝 보는 걸로.
우리 아들 화이팅!!


import 'dart:async';
import 'dart:convert';

import 'package:flutter/material.dart';
// http가 있기 때문에 http.get()이라고 쓸 수 있다. 아니면 그냥 get(). 헷갈릴 수 있다.
import 'package:http/http.dart' as http;


void main() => runApp(MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('서버/클라이언트')),
body: MyApp(),
))
);

class User {
int userId;
String name;
String email;
String phone;
Map<String, dynamic> company;

User({this.userId, this.name, this.email, this.phone, this.company});
}

Future<List<User>> fetchUsers() async {
final response = await http.get('https://jsonplaceholder.typicode.com/users');

if (response.statusCode == 200) {
// 수신 데이터는 사전(Map)의 배열이지만, 정확한 형식은 Iterable 클래스.
// Map의 형식은 이전 예제에 나온 것처럼 Map<String, dynamic>이 된다.
final users = json.decode(response.body);

// Map을 User 객체로 변환.
// Iterable 객체로부터 전체 데이터에 대해 반복
List<User> usersMap = [];
for(var user in users) { // user는 Map<String, dynamic>
usersMap.add(User(
userId: user['id'],
name: user['name'],
email: user['email'],
phone: user['phone'],
company: user['company'],
));
}
return usersMap;
}

throw Exception('데이터 수신 실패!');
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Center 위젯이 없으면 데이터를 가져오는 동안 인디케이터가 좌상단에 표시된다.
return Center(
child: FutureBuilder(
future: fetchUsers(), // User 배열 반환
builder: (context, snapshot) {
if (snapshot.hasData) {
List<User> userArray = snapshot.data; // 정확한 형식으로 변환
return ListView.builder(
itemCount: userArray.length, // 필요한 개수만큼 아이템 생성
itemExtent: 100.0,
itemBuilder: (context, index) => makeRowItem(userArray[index], index),
);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}

// 데이터를 로딩하는 동안 표시되는 인디케이터
return CircularProgressIndicator();
},
),
);
}

// 리스트뷰의 항목 생성. idx는 항목의 색상을 달리 주기 위해.
Widget makeRowItem(User user, int idx) {
return Container(
child: Column(
children: <Widget>[
Text(user.name, style: TextStyle(fontSize: 21, color: Colors.white)),
Text(user.email, style: TextStyle(fontSize: 21, fontWeight: FontWeight.bold)),
],
),
padding: EdgeInsets.only(top: 20.0),
color: idx % 2 == 1 ? Colors.blueGrey : Colors.orange[300],
);
}
}