Pagination List Data pada Flutter




Selamat Pagi 😊
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...'
  },
 ],
}

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}';  
jsonSerializable : convert data json ke bentuk model, sehingga kita tidak perlu menginisialisasi satu persatu data. Kita tinggal menggunakan perintah Post.fromJson(arrayJson)  untuk mengconvert data json ke bentuk model. Setelah file tersebut berhasil dibuat jangan lupa untuk menjalankan code berikut untuk membuild file baru post.g.dart secara otomatis.

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');
  }
 }
}

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 {}

Sedangkan untuk proses penampilan data ke ui response dari event, kita menggunakan state, berikut code secara umum. Kita dapat melakukan perubahan berdasarkan apa yang kita inginkan.

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 {}


Kemudian kita ruba PostLoaded berdasarkan keperluan kita. seperti pada contoh kali ini kita buat proses penambahan data baru pada list dan akan memberikan peringatan saat data yang ada pada database  sudah habis.

 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;
}



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 :

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,
    );
  }
}
output :









Pagination List Data pada Flutter Pagination List Data pada Flutter Reviewed by sdiik on April 19, 2020 Rating: 5

No comments:

Powered by Blogger.