Flutterで無限スクロールを手早く実装する方法
今回は、Flutterで無限スクロールを実装していきます。
Infinite Scroll Paginationを使います。
全体のソースコードはこちら
Infinite Scroll Paginationインストール
以下のコマンドでインストールします。
flutter pub add infinite_scroll_pagination
モックAPIを作成
以下のようなJSONデータを想定します。
{
"total": 72,
"per_page": 10,
"current_page": 3,
"last_page": 8,
"from": 31,
"to": 40,
"data":[
{
// Record...
},
{
// Record...
}
]
}
以下のようなモックAPIを用意します。
import 'dart:convert';
final post = {
'title': 'Flutterで無限スクロールを手早く実装する方法',
'thumbnail':
'https://techinit.co.jp/wp-content/uploads/2024/06/flutter-inifinite-scroll-pagination.png',
'body': List.generate(10, (_) => 'ここにテキスト ').join(),
'published_at': '2024/01/01 19:24',
'updated_at': '2024/07/01 20:48',
};
Future<String> postsRes({required int page}) async {
await Future.delayed(const Duration(seconds: 2));
const total = 72;
const perPage = 10;
final posts = List.generate(total, (_) => post);
return jsonEncode({
'total': total,
'per_page': perPage,
'current_page': page,
'last_page': (total / perPage).ceil().toInt(),
'from': 10 * (page - 1) + 1,
'to': 40,
'data': posts.skip((page - 1) * 10).take(10).toList(),
});
}
無限スクロール実装
画面表示部分は以下のようになります。
import 'package:flutter/material.dart';
import 'package:flutter_infinite_scroll_example/api.dart';
import 'package:flutter_infinite_scroll_example/models/post/post.dart';
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: _MyHomePage(),
);
}
}
class _MyHomePage extends StatefulWidget {
const _MyHomePage();
@override
State<_MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<_MyHomePage> {
static const _pageSize = 10;
final PagingController<int, Post> _pagingController =
PagingController(firstPageKey: 1);
@override
void initState() {
super.initState();
_pagingController.addPageRequestListener((pageKey) {
_fetchPage(pageKey);
});
}
Future<void> _fetchPage(int pageKey) async {
try {
final newItems = await getPosts(page: pageKey);
final isLastPage = newItems.data.length < _pageSize;
if (isLastPage) {
_pagingController.appendLastPage(newItems.data);
} else {
final nextPageKey = pageKey + 1;
_pagingController.appendPage(newItems.data, nextPageKey);
}
} catch (error) {
_pagingController.error = error;
}
}
@override
void dispose() {
_pagingController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('記事一覧'),
),
body: PagedListView<int, Post>(
pagingController: _pagingController,
builderDelegate: PagedChildBuilderDelegate<Post>(
itemBuilder: (context, item, index) => _PostView(post: item),
),
),
);
}
}
class _PostView extends StatelessWidget {
final Post post;
const _PostView({required this.post});
@override
Widget build(BuildContext context) {
return ListTile(
leading: Image.network(post.thumbnail),
title: Text(post.title),
subtitle: Text(post.published_at));
}
}
この記事へのコメントはありません。