[Flutter Web × Supabase] Pagination の実装をしてみた
Flutter大学 Advent Calendar 2023 4日目 です。
個人開発で Pagination を実装する機会があったので記事にしていきます。
いきなりですが皆さん Pagination の読み方を知っていますか? 私はつい、最近までページネーションと読んでいましたが本来の読み方は パジネーション(パージネーション)です。
話が逸れたので本題に戻ります。
本記事について
以下のスクショにあるように Flutter で Pagination を実装についてまとめています。
Pagination の Widget で以下のパッケージが使いやすかったのでこれを使っていきます。
Supabase を用いて Flutter Web で Pagination の実装について紹介します。また、状態管理は Riverpod を使用します。
本記事は heyhey さんの 記事を活用させてもらっています。そのため、Supabase の基本的な部分は省略しています。
環境
バージョン | |
---|---|
Flutter | 3.13.7 |
dart | 3.1.3 |
使用パッケージ
dependencies:
flutter_web_pagination: ^0.0.3
supabase_flutter: ^1.10.25
flutter_riverpod: ^2.4.9
実装
サンプルプロジェクトです。
lib/
├ controller/
│ ├ current_page_controller.dart
│ └ people_controller.dart
├ model/
│ └ people.dart
├ page/
│ └ home_page.dart
├ widget/
│ ├ custom_list_tile_widget.dart
│ └ pagination_widget.dart
└ main.dart
テストデータを作成
以下のサイトで CSV のデータを作成します。出力行数は100以上あればいいと思います。
Supabase の Table Editor の画面中央にある Create a new table をクリックし、右下あたりに Import data via spreadsheet があるのでクリックすると、CSV のファイルをアップロードできる画面が開くので先程、作成した CSV ファイルをアップロードします。
コピペで動く Pagination 一部紹介
/// 現在のページ数を管理する
class CurrentPageNotifier extends AutoDisposeNotifier<int> {
int build() {
// ページ数を返す
// 初期値は 1 ページ目のため 1 を返す
return 1;
}
/// ボタンが押されたタイミングで更新をかける
void changePage(int value) {
state = value;
}
}
/// 全件取得する
/// Pagination を表示する際にボタンの数は総データ数にされるので把握しておかなといけない
final fetchAllPeopleProvider = StreamProvider.autoDispose<List<People>>(
(ref) async* {
final data = await client
.from('people')
.select<PostgrestList>('family, name')
.order('id', ascending: false);
yield data.map(People.fromJson).toList();
},
);
/// currentPageNotifierProvider の値に応じて、データを取得する
final fetchPerPagePeopleProvider = StreamProvider.autoDispose<List<People>>(
(ref) async* {
final currentPage = ref.watch(currentPageNotifierProvider);
final data = await client
.from('people')
.select<PostgrestList>('family, name')
.order('id', ascending: false)
// 本サンプルでは 1 ページあたり 10 件表示する
.range(currentPage * 10 - 10, currentPage * 10 - 1)
.limit(10);
yield data.map(People.fromJson).toList();
},
);
class PaginationWidget extends ConsumerWidget {
const PaginationWidget({super.key});
Widget build(BuildContext context, WidgetRef ref) {
/// 現在のページ数を取得
final currentPage = ref.watch(currentPageNotifierProvider);
/// 総件数を取得
final data = ref.watch(fetchAllPeopleProvider).value?.length;
/// 1 ページあたりの表示件数
const itemsPerPage = 10;
// 総件数が 0 または null の場合は Pagination を表示しない
if (data == null || data == 0) {
return const SizedBox();
}
return WebPagination(
// ボタンが押されたタイミングでの処理
onPageChanged: (page) {
ref.read(currentPageNotifierProvider.notifier).changePage(page);
},
// 現在のページ数
currentPage: currentPage,
// 総ページ数
// currentPage が 1 から始まるため、1 を足す
// (data - 1) は data が [itemsPerPage] の値の倍数のとき、
// -1 をしないと総ページ数が 1 増えてしまうため、-1 をする
totalPage: (data - 1) ~/ itemsPerPage + 1,
// 表示するボタン数
displayItemCount: 7,
);
}
}
まとめ
本記事では、Supabase を用いてFlutter Web で Pagination
の実装について紹介しました。flutter_web_paginationパッケージを使用し、サンプルプロジェクトを通じて具体的なコードを示しました。
この記事が Flutter Web での Pagination
の実装についての理解を深める一助となれば幸いです。
ありがとうございました!
Discussion