Ditengah pandemi corona yang masih melanda, kali ini kita akan mencoba untuk membuat pagination pada flutter. dimana pagination biasanya digunakan untuk mengatasi problem kumpulan data yang sangat banyak, sehingga digunakan pagination. Pagination dapat meningkatkan perform dari aplikasi dan memanagement RAM agar tidak terlalu terpakai banyak saat proses pengambilan dan penampilan data. cara kerja dari pagination adalah menampilkan data berdasarkan limit yang diinginkan dan meloading kembali data selanjutnya jika diinginkan.
misalnya kita memiliki array json data seperti berikut :
{
[
{
'id':1,
'title': 'virus corona',
'body': 'Virus corona telah melanda indonesia sebulan terakhir...'
},
{
'id':2,
'title': 'Gunakan Masker',
'body': 'Gunakan Marker untuk mengurangi penyebaran virus...'
},
],
}
[
{
'id':1,
'title': 'virus corona',
'body': 'Virus corona telah melanda indonesia sebulan terakhir...'
},
{
'id':2,
'title': 'Gunakan Masker',
'body': 'Gunakan Marker untuk mengurangi penyebaran virus...'
},
],
}
Pertama kita buat dulu model datanya :
part 'Post.g.dart'
@jsonSerializable()
class Post extends Equatable{
final int id;
final String title;
final String body;
const Post({this.id, this.title, this.body});
@override
List<Object> get props => [id, title, body];
factory Post.fromJson(Map<String, dynamic> json) => _$PostFromJson(json);
Map<String, dynamic> toJson() => _$PostToJson(this);
@override
String toString() => 'Post {id: $id}';
}
flutter pub run build_runner build
Setelah pembuatan model berhasil dilakukan, kemudian kita buat api provider, pada percobaan ini kita menggunakan Dio library untuk proses hit data dari backend.
class ApiNewsProvider{
final String _baseUrl = 'https://jsonplaceholder.typicode.com';
Future<List<Post>> fetchPosts(int startIndex, int limit) async {
try{
final response = await Dio().get('$_baseUrl/posts_start=$startIndex&_limit=$limit');
final data = response.data as List;
return data.map((rawPost) {return Post.fromJson(rawPost);}).toList();
}catch(_){
throw Exception('error fetching posts');
}
}
}
Full Code https://github.com/ioacode/MaybeHelp/blob/master/TestingListDataBloc/api/news_provider.dart
Pertama kita buat dulu file event. file ini berisikan class untuk mendeklarasikan apa yang diinginkan user.
abstract class PostEvent extends Equatable {
@override
List<Object> get props => [];
}
class Fetch extends PostEvent {}
@override
List<Object> get props => [];
}
class Fetch extends PostEvent {}
import 'package:equatable/equatable.dart';
import 'package:test_helloworld/TestingListDataBloc/models/models.dart';
abstract class PostState extends Equatable {
const PostState();
@override
List<Object> get props => [];
}
//awal inisialisasi
class PostUninitialized extends PostState {}
//initialisasi saat error
class PostError extends PostState {}
//initialisasi saaa loaded
class PostLoaded extends PostState {}
import 'package:test_helloworld/TestingListDataBloc/models/models.dart';
abstract class PostState extends Equatable {
const PostState();
@override
List<Object> get props => [];
}
//awal inisialisasi
class PostUninitialized extends PostState {}
//initialisasi saat error
class PostError extends PostState {}
//initialisasi saaa loaded
class PostLoaded extends PostState {}
Full Code https://github.com/ioacode/MaybeHelp/blob/master/TestingListDataBloc/bloc/blocNews/news_state.dart
class PostLoaded extends PostState {
final List<Post> posts;
final bool hasReachedMax;
const PostLoaded({
this.posts,
this.hasReachedMax,
});
PostLoaded copyWith({
List<Post> posts,
bool hasReachedMax,
}) {
return PostLoaded(
posts: posts ?? this.posts,
hasReachedMax: hasReachedMax ?? this.hasReachedMax,
);
}
@override
List<Object> get props => [posts, hasReachedMax];
@override
String toString() =>
'PostLoaded { posts: ${posts.length}, hasReachedMax: $hasReachedMax }';
}
copyWith : code flutter yang berfungsi untuk menambahkan data baru pada list data. sehingga data yang lama yang terdapat pada list tidak akan terhapus.
get props : berguna untuk proses penyimpanan data dan menyimpan kondisi data. hal ini sangat berguna pada proses pagination, untuk proses update data dan informasi data sekarang.
selanjutnya kita buat file yang berisi logic, saat proses pengambilan data :
class PostBloc extends Bloc<PostEvent, PostState> {
final ApiNewsRepository apiNewsRepository = new ApiNewsRepository();
@override
get initialState => PostUninitialized();
@override
Stream<PostState> mapEventToState(PostEvent event) async* {
final currentState = state;
if (event is Fetch && !_hasReachedMax(currentState)) {
try {
if (currentState is PostUninitialized) {
final posts = await apiNewsRepository.fetchNews(0, 20);
yield PostLoaded(posts: posts, hasReachedMax: false);
return;
}
if (currentState is PostLoaded) {
final posts = await apiNewsRepository.fetchNews(currentState.posts.length, 20);
yield posts.isEmpty
? currentState.copyWith(hasReachedMax: true)
: PostLoaded(
posts: currentState.posts + posts,
hasReachedMax: false,
);
}
} catch (_) {
yield PostError();
}
}
}
bool _hasReachedMax(PostState state) =>
state is PostLoaded && state.hasReachedMax;
}
Full Code https://github.com/ioacode/MaybeHelp/blob/master/TestingListDataBloc/bloc/blocNews/news_bloc.dart
Setelah itu kita buat UI untuk menampilkan data tersebut, pertama kita buat terlebih dahulu Kerangka dasarnya untuk menampilkan widget - widget nya biar lebih mudah,
class MainListDatat extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter List',
home: Scaffold(
appBar: AppBar(
title: Text('News'),
),
body: BlocProvider(create: (context) => PostBloc()..add(Fetch()),
child: NewsUi(),
),
),
);
}
}
Sedangkan Untuk NewsUinya sebagai berikut :@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter List',
home: Scaffold(
appBar: AppBar(
title: Text('News'),
),
body: BlocProvider(create: (context) => PostBloc()..add(Fetch()),
child: NewsUi(),
),
),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:test_helloworld/TestingListDataBloc/bloc/bloc.dart';
import 'package:test_helloworld/TestingListDataBloc/models/models.dart';
class NewsUi extends StatefulWidget {
@override
_NewsUiState createState() => _NewsUiState();
}
class _NewsUiState extends State<NewsUi> {
final _scrollController = ScrollController();
final _scrollThreshold = 200.0;
PostBloc _postBloc;
@override
void initState() {
super.initState();
_scrollController.addListener(_onScroll);
_postBloc = BlocProvider.of<PostBloc>(context);
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
void _onScroll() {
final maxScroll = _scrollController.position.maxScrollExtent;
final currentScroll = _scrollController.position.pixels;
if (maxScroll - currentScroll <= _scrollThreshold) {
_postBloc.add(Fetch());
}
}
@override
Widget build(BuildContext context) {
return BlocBuilder<PostBloc, PostState>(
builder: (context, state) {
if (state is PostError) {
return Center(
child: Text("Failed to fetch News Data"),
);
}
if (state is PostLoaded) {
if (state.posts.isEmpty) {
return Center(
child: Text("News not Found"),
);
}
return ListView.builder(
itemBuilder: (BuildContext context, int index) {
return index >= state.posts.length
? BottomLoader()
: PostWidget(
post: state.posts[index],
);
},
itemCount: state.hasReachedMax
? state.posts.length
: state.posts.length + 1,
controller: _scrollController,
);
}
return Center(
child: CircularProgressIndicator(),
);
},
);
}
}
class BottomLoader extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
child: Center(
child: SizedBox(
width: 33.0,
height: 33.0,
child: CircularProgressIndicator(
strokeWidth: 1.5,
))));
}
}
class PostWidget extends StatelessWidget {
final Post post;
const PostWidget({Key key, @required this.post}) : super(key: key);
@override
Widget build(BuildContext context) {
return ListTile(
leading: Text(
'${post.id}',
style: TextStyle(fontSize: 10.0),
),
title: Text(post.title),
isThreeLine: true,
subtitle: Text(post.body),
dense: true,
);
}
}
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:test_helloworld/TestingListDataBloc/bloc/bloc.dart';
import 'package:test_helloworld/TestingListDataBloc/models/models.dart';
class NewsUi extends StatefulWidget {
@override
_NewsUiState createState() => _NewsUiState();
}
class _NewsUiState extends State<NewsUi> {
final _scrollController = ScrollController();
final _scrollThreshold = 200.0;
PostBloc _postBloc;
@override
void initState() {
super.initState();
_scrollController.addListener(_onScroll);
_postBloc = BlocProvider.of<PostBloc>(context);
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
void _onScroll() {
final maxScroll = _scrollController.position.maxScrollExtent;
final currentScroll = _scrollController.position.pixels;
if (maxScroll - currentScroll <= _scrollThreshold) {
_postBloc.add(Fetch());
}
}
@override
Widget build(BuildContext context) {
return BlocBuilder<PostBloc, PostState>(
builder: (context, state) {
if (state is PostError) {
return Center(
child: Text("Failed to fetch News Data"),
);
}
if (state is PostLoaded) {
if (state.posts.isEmpty) {
return Center(
child: Text("News not Found"),
);
}
return ListView.builder(
itemBuilder: (BuildContext context, int index) {
return index >= state.posts.length
? BottomLoader()
: PostWidget(
post: state.posts[index],
);
},
itemCount: state.hasReachedMax
? state.posts.length
: state.posts.length + 1,
controller: _scrollController,
);
}
return Center(
child: CircularProgressIndicator(),
);
},
);
}
}
class BottomLoader extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
child: Center(
child: SizedBox(
width: 33.0,
height: 33.0,
child: CircularProgressIndicator(
strokeWidth: 1.5,
))));
}
}
class PostWidget extends StatelessWidget {
final Post post;
const PostWidget({Key key, @required this.post}) : super(key: key);
@override
Widget build(BuildContext context) {
return ListTile(
leading: Text(
'${post.id}',
style: TextStyle(fontSize: 10.0),
),
title: Text(post.title),
isThreeLine: true,
subtitle: Text(post.body),
dense: true,
);
}
}
Pagination List Data pada Flutter
Reviewed by sdiik
on
April 19, 2020
Rating:
No comments: