提交 f05ef243 authored 作者: guoqing's avatar guoqing

my listView

上级 c7d72281
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'state_layout.dart';
/// 封装下拉刷新与加载更多
class MyListViewPublic extends StatefulWidget {
const MyListViewPublic(
{Key? key,
required this.itemBuilder,
required this.requestData,
this.pageSize = 10,
this.padding,
this.itemExtent,
this.controller,
this.onRefresh,
this.canLoadMore = true,
this.firstRefresh = true,
this.emptyText})
: super(key: key);
final bool canLoadMore; //是否允许上拉
final ItemBuilder itemBuilder;
final MyListController? controller;
final bool firstRefresh;
final String? emptyText;
//(page, pageSize,_requestSuccess,_requestError){}
final RequestDataCallback requestData;
/// 一页的数量,默认为10
final int pageSize;
/// padding属性使用时注意会破坏原有的SafeArea,需要自行计算bottom大小
final EdgeInsetsGeometry? padding;
final double? itemExtent;
final Function? onRefresh;
@override
State<MyListViewPublic> createState() => _MyListViewPublicState();
}
typedef RefreshCallback = Future<void> Function();
typedef LoadMoreCallback = Future<void> Function();
typedef SuccessCallback = Function(List list);
typedef RequestDataCallback = Function(
int page, int pageSize, SuccessCallback success, Function error);
typedef ItemBuilder = Function(BuildContext context, int index, dynamic item);
class _MyListViewPublicState extends State<MyListViewPublic> {
/// 是否正在加载数据
bool _isLoading = false;
int page = 1;
StateType stateType = StateType.loading;
int listItemCount = 0;
bool hasMore = true;
final List<dynamic> _dataList = [];
@override
void initState() {
if (widget.firstRefresh) {
stateType = StateType.loading;
//第一次直接获取数据
_defaultRefresh();
} else {
stateType = StateType.success;
}
super.initState();
}
@override
void didChangeDependencies() {
//绑定控制器
if (widget.controller != null) {
widget.controller?._bindEasyRefreshState(this);
}
super.didChangeDependencies();
}
void callRefresh() {
_defaultRefresh();
}
@override
Widget build(BuildContext context) {
Widget child = RefreshIndicator(
onRefresh: _defaultRefresh,
child: listItemCount == 0
? StateLayout(
type: stateType,
hintText: widget.emptyText,
)
: ScrollConfiguration(
//取消列表滑动水波纹
behavior: MyBehavior(),
child: ListView.builder(
itemCount:
!widget.canLoadMore ? listItemCount : listItemCount + 1,
padding: widget.padding,
itemExtent: widget.itemExtent,
itemBuilder: (BuildContext context, int index) {
/// 不需要加载更多则不需要添加FootView
if (!widget.canLoadMore) {
return widget.itemBuilder(context, index, _dataList[index]);
} else {
return index < listItemCount
? widget.itemBuilder(context, index, _dataList[index])
: MoreWidget(listItemCount, hasMore, widget.pageSize);
}
},
),
),
);
return SafeArea(
child: NotificationListener(
onNotification: (ScrollNotification note) {
/// 确保是垂直方向滚动,且滑动至底部
if (note.metrics.pixels == note.metrics.maxScrollExtent &&
note.metrics.axis == Axis.vertical) {
_loadMore();
}
return true;
},
child: child,
),
);
}
Future<void> _defaultRefresh() async {
widget.onRefresh?.call();
page = 1;
_dataList.clear();
listItemCount = 0;
stateType = StateType.loading;
await widget.requestData(
page, widget.pageSize, _requestSuccess, _requestError);
}
Future<void> _defaultLoadMore() async {
page++;
await widget.requestData(
page, widget.pageSize, _requestSuccess, _requestError);
}
void _requestSuccess(List? result) {
result ??= [];
_dataList.addAll(result);
listItemCount = _dataList.length;
hasMore = result.length == widget.pageSize;
if (page == 1 && (result.length == 0)) {
stateType = StateType.empty; //显示空布局
} else {
stateType = StateType.success; //显示成功布局
}
_isLoading = false;
setState(() {});
}
void _requestError(r) {
stateType = StateType.error; //显示异常布局
}
Future<void> _loadMore() async {
if (!widget.canLoadMore) {
return;
}
if (_isLoading) {
return;
}
if (!hasMore) {
return;
}
_isLoading = true;
await _defaultLoadMore();
}
}
class MyListController {
late _MyListViewPublicState _deerListViewState;
// 绑定状态
void _bindEasyRefreshState(_MyListViewPublicState state) {
_deerListViewState = state;
}
//刷新
void callRefresh() {
_deerListViewState.callRefresh();
}
}
class MoreWidget extends StatelessWidget {
const MoreWidget(
this.itemCount,
this.hasMore,
this.pageSize, {
Key? key,
}) : super(key: key);
final int itemCount;
final bool hasMore;
final int pageSize;
@override
Widget build(BuildContext context) {
TextStyle style = const TextStyle(color: Color(0x8A000000));
return Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
hasMore ? const CupertinoActivityIndicator() : const SizedBox(),
hasMore
? const SizedBox(
width: 5,
)
: const SizedBox(),
/// 只有一页的时候,就不显示FooterView了
Text(hasMore ? '正在加载中...' : (itemCount < pageSize ? '' : '没有了呦~'),
style: style),
],
),
);
}
}
//取消列表滑动水波纹
class MyBehavior extends ScrollBehavior {
@override
Widget buildOverscrollIndicator(
BuildContext context, Widget child, ScrollableDetails details) {
if (Platform.isAndroid || Platform.isFuchsia) {
return child;
} else {
return super.buildOverscrollIndicator(context, child, details);
}
}
}
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../utils/image_utils.dart';
class StateLayout extends StatefulWidget {
const StateLayout({Key? key, required this.type, this.hintText})
: super(key: key);
final StateType type;
final String? hintText;
@override
State<StateLayout> createState() => _StateLayoutState();
}
class _StateLayoutState extends State<StateLayout> {
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: SizedBox(
height: MediaQuery.of(context).size.height - 30.0,
child: widget.type == StateType.loading
? _loadingWidget()
: _otherWidget(),
),
);
}
Widget _loadingWidget() {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: const [
CupertinoActivityIndicator(radius: 16.0),
SizedBox(
width: double.infinity,
height: 16.0,
),
SizedBox(
height: 50,
),
],
);
}
Widget _otherWidget() {
switch (widget.type) {
case StateType.network:
return _buildNormalView('icon_no_wifi', '无网络连接');
case StateType.loading:
return Container();
case StateType.empty:
return _buildNormalView('icon_empty', widget.hintText ?? '暂无数据');
case StateType.error:
return _buildNormalView('icon_list_failure', '请求失败,请重试');
case StateType.success:
return Container();
}
}
Widget _buildNormalView(String img, String hintText) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Opacity(
opacity: 1,
child: Container(
height: 120.0,
width: 120.0,
decoration: BoxDecoration(
image: DecorationImage(
image: ImageUtils.getAssetImage(img),
),
),
)),
const SizedBox(
width: double.infinity,
height: 16.0,
),
Text(
hintText,
style: const TextStyle(fontSize: 14, color: Colors.grey),
),
const SizedBox(
height: 50,
),
],
);
}
}
enum StateType {
/// 无网络
network,
/// 加载中
loading,
/// 空
empty,
///异常
error,
///成功
success
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论