Membuat Infinite Scroll (Pagination) Flutter

Idris
3 min readJun 30, 2020

--

https://unsplash.com/photos/FVtG38Cjc_k
Photo by Marten Bjork on Unsplash

Pengantar

Pada umumnya ketika kita ingin menampilkan data dalam bentuk listview langsung sekaligus semuanya. Namun, bagaimana jika data yang ingin ditampilkan data yang dimiliki sangat banyak? Sebagai contoh, jika ingin menampilkan 100 data dalam bentuk listview, jika ditampilkan 100 data sekaligus maka bisa saja terjadi adalah memory leaks. Bagaimana solusi untuk mengatasi masalah tersebut? Salah satu caranya adalah dengan membuat infinite scroll pada tampilan listview. Jadi, listview akan menampilkan data secara berkala ketika proses scrolling sedang berlangsung.

Pembahasan

  • Membuat Model
class NewsModel {
String status;
int totalResults;
List<Articles> articles;

NewsModel({this.status, this.totalResults, this.articles});

NewsModel.fromJson(Map<String, dynamic> json) {
status = json['status'];
totalResults = json['totalResults'];
if (json['articles'] != null) {
articles = new List<Articles>();
json['articles'].forEach((v) {
articles.add(new Articles.fromJson(v));
});
}
}

Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['status'] = this.status;
data['totalResults'] = this.totalResults;
if (this.articles != null) {
data['articles'] = this.articles.map((v) => v.toJson()).toList();
}
return data;
}
}

class Articles {
Source source;
String author;
String title;
String description;
String url;
String urlToImage;
String publishedAt;
String content;

Articles(
{this.source,
this.author,
this.title,
this.description,
this.url,
this.urlToImage,
this.publishedAt,
this.content});

Articles.fromJson(Map<String, dynamic> json) {
source =
json['source'] != null ? new Source.fromJson(json['source']) : null;
author = json['author'];
title = json['title'];
description = json['description'];
url = json['url'];
urlToImage = json['urlToImage'];
publishedAt = json['publishedAt'];
content = json['content'];
}

Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.source != null) {
data['source'] = this.source.toJson();
}
data['author'] = this.author;
data['title'] = this.title;
data['description'] = this.description;
data['url'] = this.url;
data['urlToImage'] = this.urlToImage;
data['publishedAt'] = this.publishedAt;
data['content'] = this.content;
return data;
}
}

class Source {
String id;
String name;

Source({this.id, this.name});

Source.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
}

Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['name'] = this.name;
return data;
}
}
  • Membuat Repository
import 'dart:convert';

import 'package:flutterappinfinitescroll/model/news_model.dart';
import 'package:http/http.dart' as http;

class NewsRepository {
static Future<NewsModel> getNewsData(int currentPage) async {
final url = "https://newsapi.org/v2/top-headlines?country=us&apiKey=29c99d03194f4d46acbbceaa5#####&page=$currentPage";
final results = await http.get(url);
print("statuse kode: +${results.statusCode}");
if (results.statusCode == 200) {
NewsModel newsModel = NewsModel.fromJson(jsonDecode(results.body));
return newsModel;
}
return null;
}
}
  • Implementasi Infinite Scroll
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutterappinfinitescroll/model/news_model.dart';
import 'package:flutterappinfinitescroll/repository/news_repository.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}

class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;

@override
_MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
int currentPage = 1;
List<Articles> articles;
ScrollController scrollController = ScrollController();


bool onNotification(ScrollNotification scrollNotification) {
if (scrollNotification is ScrollUpdateNotification) {
if (scrollController.position.maxScrollExtent > scrollController.offset &&
scrollController.position.maxScrollExtent - scrollController.offset <=
50) {
setState(() {
currentPage += 1;
NewsRepository.getNewsData(currentPage).then((response) {
print('halaman sekarang: $currentPage');
if (response != null) {
articles.addAll(response.articles);
}
});
});
}
}
return true;
}


@override
void initState() {
// TODO: implement initState
super.initState();
NewsRepository.getNewsData(currentPage).then((response) {
if (response != null) {
setState(() {
articles = response.articles;
totalPages = response.totalResults;
});
}
});
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: articles == null || articles.length == 0
? Center(child: CircularProgressIndicator())
: NotificationListener(
onNotification: onNotification,
child: ListView.builder(
controller: scrollController,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.fromLTRB(40, 10, 40, 20),
child: Row(
children: <Widget>[
Flexible(
child: Text(articles[index].title),
),
Divider()
],
),
);
},
itemCount: articles.length,
),
),
);
}
}

Penjelasan kode

  • Membungkus widget listview ke dalam widget notification listener
  • Menambahkan atribute controller pada widget listview

Ketika kita melakukan scrolling, atribut onNotification akan terus memantau proses scrolling tersebut. Sembari melakukan pemantauan dalam mode ScrollUpdateNotification, dilakukan juga pengecekan apakah proses scroll sudah mencapai maksimum. Jika sudah mencapai maksimum, maka dilakukan pengambilan data sesuai dengan penambahan otomatis atribut currentPage.

Kesimpulan

Untuk menampilkan data dalam bentuk listview secara berkala dapat dilakukan dengan cara infinite scroll. Caranya adalah dengan membungkus widget listview ke dalam widget notification listener. Atribut onNotification akan memantau proses scrolling. Atribut controller pada widget listview untuk mengecek apakah posisi scroll sudah mencapai maksimum. Jika scroll sudah mencapai maksimum, maka akan dilakukan pengambilan data untuk ditampilkan ke dalam listview.

--

--