この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
大阪オフィスの山田です。育てている楓を一度枯らしてしまったのですが、幹から新しい芽が出てきました。今回はFlutterでシンプルにAPIから取得したデータを表示してみます。入力された文字を名前に含むGitHubリポジトリを検索して、リストにして表示するプログラムを実装してみました。ビジネスロジックを分けることもしていないので、大きなWidgetの中でベタに書いています。GitHubのAPIに関するドキュメントはこちら。
開発環境
flutter doctor
[✓] Flutter (Channel master, v0.9.5-pre.12, on Mac OS X 10.13.6 17G65, locale ja-JP)
[✓] Android toolchain - develop for Android devices (Android SDK 28.0.1)
[✓] iOS toolchain - develop for iOS devices (Xcode 10.0)
[✓] Android Studio (version 3.1)
✗ Flutter plugin not installed; this adds Flutter specific functionality.
✗ Dart plugin not installed; this adds Dart specific functionality.
[✓] VS Code (version 1.27.2)
[✓] Connected device (1 available)
Android Studioは確かバージョン3.2が来ていましたね。近いうちにアップデートしよう。詳細はこちら。
動作画像
iOS
Android
実装
Model
Githubのリポジトリ情報をModelにします。Named Constructorを追加して、JSONからModelを生成できるようにしています。Named Constructorについてはこちら
class GithubRepository {
/// Repository full name.
final String fullName;
/// Repository description.
final String description;
/// Language in use.
final String language;
/// Repository html url.
final String htmlUrl;
/// Count of stars.
final int stargazersCount;
/// Count of watchers.
final int watchersCount;
/// Count of forks repository.
final int forksCount;
GithubRepository.fromJson(Map<String, dynamic> json)
: fullName = json['full_name'],
description = json['description'],
language = json['language'],
htmlUrl = json['html_url'],
stargazersCount = json['stargazers_count'],
watchersCount = json['watchers_count'],
forksCount = json['forks_count'];
}
入力部分
Widget _buildInput() {
return Container(
margin: EdgeInsets.all(16.0),
child: TextField(
decoration: InputDecoration(
prefixIcon: Icon(Icons.search),
hintText: 'Please enter a search repository name.',
labelText: "search"
),
onChanged: (inputString) {
if (inputString.length >= 5) {
_searchRepositories(inputString).then((repositories) {
setState(() {
_repositories = repositories;
});
});
}
},
)
);
}
TextFieldを置いて、onChangedイベントで入力文字数が5文字以上になったら、APIをコールするメソッドを呼んでいます。取得したGithubRepositoryの一覧を更新して、再描画しています。_repositories
はState内に定義してある変数です。※エラー処理は入れてません。
APIコール部分
Future<List<GithubRepository>> _searchRepositories(String searchWord) async {
final response = await http.get('https://api.github.com/search/repositories?q=' + searchWord + '&sort=stars&order=desc');
if (response.statusCode == 200) {
List<GithubRepository> list = [];
Map<String, dynamic> decoded = json.decode(response.body);
for (var item in decoded['items']) {
list.add(GithubRepository.fromJson(item));
}
return list;
} else {
throw Exception('Fail to search repository');
}
}
APIコール部分です。レスポンスが返ってきたらJSONからGithubRepositoryの配列に変換して返却しています。
リスト部分
少し長いですが、ほとんどがデザイン部分です。
Widget _buildRepositoryList() {
return ListView.builder(
itemBuilder: (BuildContext context, int index) {
final repository = _repositories[index];
return _buildCard(repository);
},
itemCount: _repositories.length,
);
}
Widget _buildCard(GithubRepository repository) {
return Card(
margin: EdgeInsets.fromLTRB(16.0, 0.0, 16.0, 16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.all(12.0),
child: Text(
repository.fullName,
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 16.0
),
),
),
repository.language != null ? Padding(
padding: EdgeInsets.fromLTRB(12.0, 0.0, 12.0, 12.0),
child: Text(
repository.language,
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 12.0
),
),
) : Container(),
repository.description != null ? Padding(
padding: EdgeInsets.fromLTRB(12.0, 0.0, 12.0, 12.0),
child: Text(
repository.description,
style: TextStyle(
fontWeight: FontWeight.w200,
color: Colors.grey
)
),
) : Container(),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Icon(Icons.star),
SizedBox(
width: 50.0,
child: Text(repository.stargazersCount.toString()),
),
Icon(Icons.remove_red_eye),
SizedBox(
width: 50.0,
child: Text(repository.watchersCount.toString()),
),
Text("Fork:"),
SizedBox(
width: 50.0,
child: Text(repository.forksCount.toString()),
),
],
),
SizedBox(height: 16.0,)
],
)
,);
}
リスト部分を作成しています。State内に宣言されているGithubRepositoryの配列をCard Widgetにして表示しています。スター数などのテキストは、SizedBoxで大きさを揃えています。Forkに該当する良いアイコンが見つからなかった...
最後に
いかがだったでしょうか。今回はベタがきでシンプルに実装しました。ビジネスロジックがViewの中に紛れ込んでしまっていますね。現在、BLoCパターンを勉強中ですので、そちらのアーキテクチャパターンを使って実装し直して、ブログにしようと考えています。