//limit-skip
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class PaginatedApiListView extends StatefulWidget {
@override
_PaginatedApiListViewState createState() => _PaginatedApiListViewState();
}
class _PaginatedApiListViewState extends State {
final ScrollController _scrollController = ScrollController();
List _products = [];
int _currentPage = 1;
final int _limit = 10;
bool _isLoading = false;
bool _hasMore = true;
@override
void initState() {
super.initState();
_fetchProducts();
_scrollController.addListener(() {
if (_scrollController.position.pixels >=
_scrollController.position.maxScrollExtent - 200 &&
!_isLoading &&
_hasMore) {
_fetchProducts();
}
});
}
Future _fetchProducts() async {
setState(() {
_isLoading = true;
});
final skip = (_currentPage - 1) * _limit;
final response = await http.get(
Uri.parse('https://dummyjson.com/products?limit=$_limit&skip=$skip'),
);
if (response.statusCode == 200) {
final data = json.decode(response.body);
final List<dynamic> newProducts = data['products'];
setState(() {
_currentPage++;
_products.addAll(newProducts);
_hasMore = _products.length < data['total']; // total = 100
_isLoading = false;
});
} else {
setState(() {
_isLoading = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to load data')),
);
}
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Paginated Products')),
body: ListView.builder(
controller: _scrollController,
itemCount: _products.length + (_isLoading || _hasMore ? 1 : 0),
itemBuilder: (context, index) {
if (index < _products.length) {
final product = _products[index];
return ListTile(
leading: CircleAvatar(
backgroundImage: NetworkImage(product['thumbnail']),
),
title: Text(product['title']),
subtitle: Text("\$${product['price']}"),
);
} else {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Center(child: CircularProgressIndicator()),
);
}
},
),
);
}
}
| List (array) | List data = jsonDecode(...) | posts.addAll(data); |
| Single Object | Map data = jsonDecode(...) | posts.add(data); |
| Object with List inside key | Map json = jsonDecode(...); List data = json['data']; | posts.addAll(data); |
//page and limit
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class LastDemo extends StatefulWidget {
const LastDemo({super.key});
@override
State createState() => _DemoState();
}
class _DemoState extends State {
List posts = [];
bool _isloading = false;
bool hasmore = true;
int currenpage = 1;
final int limit = 20;
final ScrollController scrollController = ScrollController();
@override
void initState() {
super.initState();
fetchPosts();
scrollController.addListener(_scrollListener);
}
void _scrollListener() {
if (scrollController.position.pixels >=
scrollController.position.maxScrollExtent - 200 &&
!_isloading &&
hasmore) {
fetchPosts();
}
}
Future fetchPosts() async {
setState(() {
_isloading = true;
});
final response = await http.get(Uri.parse(
'https://jsonplaceholder.typicode.com/posts?_page=$currenpage&_limit=$limit'));
if (response.statusCode == 200) {
final List<dynamic> data = jsonDecode(response.body);
setState(() {
currenpage++;
posts.addAll(data);
_isloading = false;
if (data.length < limit) {
hasmore = false;
}
});
}
}
@override
void dispose() {
scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Paginated Posts")),
body: ListView.builder(
controller: scrollController,
itemCount: posts.length + (_isloading && hasmore ? 1 : 0),
itemBuilder: (context, index) {
if (index < posts.length) {
final post = posts[index];
return ListTile(
title: Text(post['title']),
subtitle: Text(post['body']),
);
} else {
return const Padding(
padding: EdgeInsets.all(12),
child: Center(child: CircularProgressIndicator()),
);
}
},
),
);
}
}
Top comments (0)