In this project we will read Employee record from JSON file stored in assets folder and show in list with employee name and his department. When user reach at last item, will show CircularProgressIndicator at bottom of list and we will again read same JSON file and add data in current list. Here, we will use sliver list.
The following are main steps :-
Create EmployeeList StatefulWidget class
Create SliverList and list item
Create Employee model class.
Read data from JSON file in assets and set to list.
Create project in Visual Studio by ctrl+shift+p, enter project name lazy_list and hit enter.
It will take some time to create your project structure.
main.dart
void main(List<String> args) {
runApp(EmployeeList());
}
Create a EmployeeList StatefulWidget class and override initState().
class EmployeeList extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return EmployeeState();
}
}
class EmployeeState extends State<EmployeeList> {
List<Employee> _employeeList = [];
bool _isLoading;
bool _hasMore = true;
ScrollController _scrollController = ScrollController();
@override
void initState() {
super.initState();
_isLoading = true;
_scrollController.addListener(_scrollListener);
Future.delayed(Duration(milliseconds: 3), () {
_getEmployeeList();
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: Text("Lazy Load"),
),
body: _buildListView(),
),
);
}
}
_scrollListener method used to determine whether the scrolling is close to bottom.
If list reached at bottom, we again read data from JSON and add to list.
_scrollListener() {
if (_scrollController.offset >=
_scrollController.position.maxScrollExtent &&
!_scrollController.position.outOfRange &&
!_isLoading) {
_getEmployeeList();
}
}
Now lets create list. Here we are using sliverlist, becuase of SliverToBoxAdapter it's eazy to show loader at list bottom.
Widget _buildListView() {
if (_isLoading && _employeeList.length == 0) {
return _loadingPopup();
}
return Padding(
padding: const EdgeInsets.all(8),
child: _employeeList.length == 0
? Center(
child: Text("No record found."),
)
: CustomScrollView(
controller: _scrollController,
slivers: <Widget>[
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return _listItem(_employeeList[index]);
},
childCount: (_employeeList.length),
addAutomaticKeepAlives: false,
),
),
SliverToBoxAdapter(
child: _isLoading ? _loadingPopup() : SizedBox(),
),
],
),
);
}
Lets create list item. Here we show Employee name with his department.
Widget _listItem(Employee _detail) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Text(
_detail.empName,
style: TextStyle(fontSize: 14, color: Colors.black),
),
SizedBox(
height: 2,
),
Text(
_detail.empDepartment,
style: TextStyle(fontSize: 12, color: Colors.grey),
),
],
),
);
}
And _loadingPopup returns CircularProgressIndicator, to show while reading data.
Widget _loadingPopup() {
return Container(
margin: EdgeInsets.only(top: 24, bottom: 16),
alignment: Alignment.center,
child: CircularProgressIndicator(
backgroundColor: Colors.grey,
valueColor: AlwaysStoppedAnimation<Color>(
Colors.blue,
),
),
);
}
Until now, we have create EmployeeList StatefulWidget, having sliverlist with listitem. Let set data to this list. For that we parse data from JSON file. First create model class Employee.dart to hold parsed data.
class Employee {
String empName;
String empDepartment;
Employee.fromJson(Map<String, dynamic> json) {
empName = json["name"];
empDepartment = json["department"];
}
}
And create employee.json file at assets/resources/json
[
{
"id": 1,
"name": "Employee 1",
"department": "Production"
},
{
"id": 2,
"name": "Employee 2",
"department": "Engineering"
},
{
"id": 3,
"name": "Employee 3",
"department": "Designing"
},
{
"id": 4,
"name": "Employee 4",
"department": "Store"
},
{
"id": 5,
"name": "Employee 5",
"department": "Management"
},
{
"id": 6,
"name": "Employee 6",
"department": "Human Resource"
},
{
"id": 7,
"name": "Employee 7",
"department": "Information Technology"
},
{
"id": 8,
"name": "Employee 8",
"department": "Marketing"
},
{
"id": 9,
"name": "Employee 9",
"department": "Sales"
},
{
"id": 10,
"name": "Employee 10",
"department": "Quality Assurance"
},
{
"id": 11,
"name": "Employee 11",
"department": "Security"
},
{
"id": 12,
"name": "Employee 12",
"department": "Account"
}
]
Create _getEmployeeList function to read and parsed JSON data.
void _getEmployeeList() async {
if (!_hasMore) return;
setState(() {
_isLoading = true;
});
await new Future.delayed(new Duration(seconds: 2));
String jsonString = await _loadEmployeeData();
var jsonResult = json.decode(jsonString);
if (jsonResult != null) {
var list =
jsonResult.map<Employee>((json) => Employee.fromJson(json)).toList();
_employeeList.addAll(list);
_isLoading = false;
} else {
_hasMore = false;
}
if (mounted) setState(() {});
}
Future<String> _loadEmployeeData() async {
return await rootBundle.loadString('assets/resources/json/employee.json');
}
To show divider in listitem, change in sliverlist code
SliverList(delegate: SliverChildBuilderDelegate(
(context, index) {
if (index.isOdd) {
return Divider(color: Colors.blueGrey);
}
return _listItem(_employeeList[index ~/ 2]);
},
childCount: (_employeeList.length * 2) - 1,
addAutomaticKeepAlives: false,
),
),
The final code
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:lazyload/model/employee.dart';
void main(List<String> args) {
runApp(EmployeeList());
}
class EmployeeList extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return EmployeeState();
}
}
class EmployeeState extends State<EmployeeList> {
List<Employee> _employeeList = [];
bool _isLoading = true;
bool _hasMore = true;
ScrollController _scrollController = ScrollController();
@override
void initState() {
super.initState();
_isLoading = true;
_scrollController.addListener(_scrollListener);
Future.delayed(Duration(milliseconds: 3), () {
_getEmployeeList();
});
}
_scrollListener() {
if (_scrollController.offset >=
_scrollController.position.maxScrollExtent &&
!_scrollController.position.outOfRange &&
!_isLoading) {
_getEmployeeList();
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: Text("Lazy Load"),
),
body: _buildListView(),
),
);
}
Widget _buildListView() {
if (_isLoading && _employeeList.length == 0) {
return _loadingPopup();
}
return Padding(
padding: const EdgeInsets.all(8),
child: _employeeList.length == 0
? Center(
child: Text("No record found."),
)
: CustomScrollView(
controller: _scrollController,
slivers: <Widget>[
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
if (index.isOdd) {
return Divider(color: Colors.blueGrey);
}
return _listItem(_employeeList[index ~/ 2]);
},
childCount: (_employeeList.length * 2) - 1,
addAutomaticKeepAlives: false,
),
),
SliverToBoxAdapter(
child: _isLoading ? _loadingPopup() : SizedBox(),
),
],
),
);
}
Widget _listItem(Employee _detail) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Text(
_detail.empName,
style: TextStyle(fontSize: 14, color: Colors.black),
),
SizedBox(
height: 2,
),
Text(
_detail.empDepartment,
style: TextStyle(fontSize: 12, color: Colors.grey),
),
],
),
);
}
Widget _loadingPopup() {
return Container(
margin: EdgeInsets.only(top: 24, bottom: 16),
alignment: Alignment.center,
child: CircularProgressIndicator(
backgroundColor: Colors.grey,
valueColor: AlwaysStoppedAnimation<Color>(
Colors.blue,
),
),
);
}
void _getEmployeeList() async {
if (!_hasMore) return;
setState(() {
_isLoading = true;
});
await new Future.delayed(new Duration(seconds: 2));
String jsonString = await _loadEmployeeData();
var jsonResult = json.decode(jsonString);
if (jsonResult != null) {
var list =
jsonResult.map<Employee>((json) => Employee.fromJson(json)).toList();
_employeeList.addAll(list);
_isLoading = false;
} else {
_hasMore = false;
}
if (mounted) setState(() {});
}
Future<String> _loadEmployeeData() async {
return await rootBundle.loadString('assets/resources/json/employee.json');
}
}
コメント