非同期でFirestoreから取得したデータを一覧で表示するための実装について記事を書いていきたいと思います。データを一覧で表示する方法については、FlutterのGridViewウィジェットを利用する実装で紹介したいと思います。
Firestoreのデータ構造
今回の記事で紹介するFirestoreのデータ構造は以下のとおりです。
Collectionの中にドキュメントが一覧であり、各ドキュメントはtitleを持っています。
全体の実装
最初に全体の実装ですが、以下のようになります。
この後の章で要点について解説していきます。
class SakeGridViewWidget extends StatelessWidget {
final Color color;
final String title;
const SakeGridViewWidget({Key? key, required this.color, required this.title}) : super(key: key);
@override
Widget build(BuildContext context) {
var assetsImage = "images/ic_sake.png";
return MaterialApp(
title: 'Grid List',
home: Scaffold(
body: StreamBuilder(
stream: FirebaseFirestore.instance.collection('BrandList').snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
}
return GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 10.0, // 縦
mainAxisSpacing: 10.0, // 横
childAspectRatio: 0.7),
itemCount: snapshot.data!.docs.length,
padding: const EdgeInsets.all(5.0),
itemBuilder: (BuildContext context, int index) {
return Container(
child: GestureDetector(
child: Column(
children: <Widget>[
Image.asset(assetsImage, fit: BoxFit.cover,),
Container(
margin: const EdgeInsets.all(10.0),
child: Text(snapshot.data!.docs[index]['title']),
),
],
)),
padding: const EdgeInsets.all(10.0),
decoration: BoxDecoration(
color: color,
boxShadow: const [
BoxShadow(
color: Colors.grey,
offset: Offset(5.0, 5.0),
blurRadius: 10.0,
)
],
),
);
},
);
}),
),
);
}
}
Documentの一覧を非同期で取得する
Firestoreからデータの一覧を取得する場合、Collectionに対してスナップショットを取得する形となります。
スナップショットは非同期で取得する事になり、返り値はStream<QuerySnapshot<T>>
型となっているため、StreamBuilderウィジェットを利用して取得します。
body: StreamBuilder(
stream: FirebaseFirestore.instance.collection('BrandList').snapshots(),
データ取得中のインジケータの表示
非同期でのデータ取得中であることがわかるように、取得中の間だけインジケータを表示する実装は以下の部分になります。データ取得が完了するとsnapshot
に値が入ることでif文を抜けられます。
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
}
タイル状にデータを一覧表示
縦に3列のタイル状になるようにデータをGridViewに表示する実装は以下の部分になります。
return GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 10.0, // 縦
mainAxisSpacing: 10.0, // 横
childAspectRatio: 0.7),
itemCount: snapshot.data!.docs.length,
padding: const EdgeInsets.all(5.0),
各パラメータの意味は以下となります。
crossAxisCount
:縦に何列並べるかの設定
crossAxisSpacing
:縦の並びの余白
mainAxisSpacing
:横の並びの余白
childAspectRatio
:1つのタイルの縦横比率
itemCount
:表示するデータの個数
padding
:GridViewの周りの余白
Documentデータを各タイルに表示する
GridViewの各タイルにデータを表示する実装は以下の部分になります。
itemBuilder: (BuildContext context, int index) {
return Container(
child: GestureDetector(
child: Column(
children: <Widget>[
Image.asset(assetsImage, fit: BoxFit.cover,),
Container(
margin: const EdgeInsets.all(10.0),
child: Text(snapshot.data!.docs[index]['title']),
),
],
)),
assetsImage
はサンプルのイメージ画像を表示しています。
Container
部分が、コレクションのスナップショットから各Documentのtitle
フィールドのデータの取得する処理となっています。itemBuilder
の引数でもらっているindex
が1つ1つのDocumentデータにアクセスするインデックスとなっています。
2次元配列のようなアクセス方法が可能で、
snapshot.data!.docs[0]['title']
ならabcDoc
のtitle
、
snapshot.data!.docs[1]['title']
ならbcdDoc
のtitle
・・・とアクセスできます。
さいごに
私がFlutterを学ぶにあたり、参考にしたサイト集を別の記事でまとめていますので、こちらも是非読んでみてもらえたらと思います。