@override void operator []=(int index, T value) { // TODO: implement []= _array[index] = value; }
bool get hasMore => true; bool isLoading = false;
IndicatorStatus indicatorStatus = IndicatorStatus.None;
Future loadMore() async { if (isLoading || !hasMore) return true; // TODO: implement loadMore
var preStatus = indicatorStatus; indicatorStatus = this.length == 0 ? IndicatorStatus.FullScreenBusying : IndicatorStatus.LoadingMoreBusying;
if (preStatus == IndicatorStatus.Error) { onStateChanged(this); } isLoading = true; var isSuccess = await loadData(); isLoading = false; if (isSuccess) { if (this.length == 0) indicatorStatus = IndicatorStatus.Empty; } else { indicatorStatus = IndicatorStatus.Error; } onStateChanged(this); return isSuccess; }
Future loadData() async { return true; }
@override Future onRefresh() async { // TODO: implement OnRefresh }
@override int get length => _array.length; set length(int newLength) => _array.length = newLength;
@override void onStateChanged(LoadingMoreBase source) { // TODO: implement notice super.onStateChanged(source); } }
class _LoadingMoreBloc { final _rebuild = new StreamController<LoadingMoreBase>.broadcast(); Stream<LoadingMoreBase> get rebuild => _rebuild.stream;
void onStateChanged(LoadingMoreBase source) { if (!_rebuild?.isClosed) _rebuild.sink.add(source); }
void dispose() { _rebuild?.close(); } }
继承于ListBase 方便后面继承
3个重要的方法: 用于加载更多
Future loadMore() async
用于刷新(重置列表)
Future onRefresh() async
用于获取数据,loadmore会调用这个方法,一般我们override的这个方法,loadmore里面有一些状态控制,如果你需要overrdie loadmore方法,注意查看下之前里面的状态控制代码
Future loadData() async
3个重要的属性: hasMore 判断是否还有更多 isLoading 判断是否正在获取数据 indicatorStatus 判断当前列表的状态
_LoadingMoreBloc 可以通过这个类来通知streambuilder更新UI
下面是如何继承使用这个base 类
class TuChongRepository extends LoadingMoreBase { int pageindex = 1;
@override // TODO: implement hasMore bool _hasMore = true; bool get hasMore => _hasMore && length < 20;
@override Future onRefresh() async { // TODO: implement onRefresh pageindex = 1; return loadMore(); }
@override Future loadData() async { // TODO: implement getData String url = “”; if (this.length == 0) { url = “https://api.tuchong.com/feed-app”; } else { int lastPostId = this[this.length - 1].post_id; url = “https://api.tuchong.com/feed-app?post_id=KaTeX parse error: Expected 'EOF', got '&' at position 13: {lastPostId}&?page={pageindex}&type=loadmore”; } bool isSuccess = false; try { //to show loading more clearly, in your app,remove this await Future.delayed(Duration(milliseconds: 500, seconds: 1));
var result = await HttpFactory.getInstance().getHttpClient().get(url);
var source = TuChongSource.fromJson(json.decode(result.body)); if (pageindex == 1) { this.clear(); }
source.feedList.forEach((item) { if (item.hasImage && !this.contains(item) && hasMore) { this.add(item); } });
_hasMore = source.feedList.length != 0; pageindex++; isSuccess = true; } catch (exception) { isSuccess = false; print(exception); } return isSuccess; } }
将你请求列表的代码加到getData方法里面,这样数据源的准备就好了。
下面说说UI组件 这一部分分为ListView/GridView 和SliverList/SliverGrid
ListView/GridView
LoadingMoreList 里面的部分代码,StreamBuilder为更新UI,NotificationListener为了监听滑动状态
class LoadingMoreList extends StatelessWidget { final ListConfig listConfig;
LoadingMoreList(this.listConfig,{Key key})
-
super(key: key);
@override
Widget build(BuildContext context) {
return StreamBuilder(
builder: (d, s) {
return NotificationListener(
//key: _key,
onNotification: _handleScrollNotification,
child: NotificationListener(
onNotification: _handleGlowNotification,
child: listConfig.buildContent(context, s.data)),
);
},
stream: listConfig.sourceList?.rebuild,
);
}
}
ListConfig 里面提供了ListView/GridView的全部参数,这里我也提供了去掉滚动越界效果(就是列表滚不动的时候出现的水波纹效果)的2个属性showGlowLeading/showGlowTrailing。
final Axis scrollDirection; final bool reverse; final ScrollController controller; final bool primary; final ScrollPhysics physics; final bool shrinkWrap; final EdgeInsetsGeometry padding; final double itemExtent; final int itemCount; final bool addAutomaticKeepAlives; final bool addRepaintBoundaries; final bool addSemanticIndexes; final double cacheExtent; final int semanticChildCount;
/// Whether to show the overscroll glow on the side with negative scroll /// offsets. final bool showGlowLeading;
/// Whether to show the overscroll glow on the side with positive scroll /// offsets. final bool showGlowTrailing;
ListConfig( @required itemBuilder, @required sourceList, { this.showGlowLeading: true, this.showGlowTrailing: true, LoadingMoreIndicatorBuilder indicatorBuilder, SliverGridDelegate gridDelegate, this.scrollDirection = Axis.vertical, this.reverse = false, this.controller, this.primary, this.physics, this.shrinkWrap = false, this.padding, this.itemExtent, this.itemC
《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享
ount, this.addAutomaticKeepAlives = true, this.addRepaintBoundaries = true, this.addSemanticIndexes = true, this.cacheExtent, this.semanticChildCount, }) : super(itemBuilder, sourceList, indicatorBuilder: indicatorBuilder, gridDelegate: gridDelegate);
sourceList 就是之前我们完成的loadingmore 数据源 itemBuilder 是每个item长什么样子
Demo code
class ListViewDemo extends StatefulWidget { @override _ListViewDemoState createState() => _ListViewDemoState(); }
class _ListViewDemoState extends State { TuChongRepository listSourceRepository; @override void initState() { // TODO: implement initState listSourceRepository = new TuChongRepository(); super.initState(); }
@override void dispose() { listSourceRepository?.dispose(); // TODO: implement dispose super.dispose(); }
@override Widget build(BuildContext context) { return Material( child: Column( children: [ AppBar( title: Text(“ListViewDemo”), ), Expanded( child: LoadingMoreList( ListConfig( ItemBuilder.itemBuilder, listSourceRepository, // showGlowLeading: false, // showGlowTrailing: false, padding: EdgeInsets.all(0.0)),), ) ], ), ); } }
这样子实现了一个加载更多的ListView,如果是GridView的话请给gridDelegate赋值.
SliverList/SliverGrid 支持多个loadmore列表 SliverListConfig 里面包含了SliverList/SliverGrid里面的参数
//config for SliverList and SliverGrid class SliverListConfig extends LoadingMoreListConfig { //whether show no more . bool showNoMore = true; //whether show fullscreenLoading for multiple sliver bool showFullScreenLoading = true;
final bool addAutomaticKeepAlives; final bool addRepaintBoundaries; final bool addSemanticIndexes; final SemanticIndexCallback semanticIndexCallback; final int semanticIndexOffset; final int childCount;
SliverListConfig( @required itemBuilder, @required sourceList, { LoadingMoreIndicatorBuilder indicatorBuilder, SliverGridDelegate gridDelegate, this.addAutomaticKeepAlives = true, this.addRepaintBoundaries = true, this.addSemanticIndexes = true, this.semanticIndexCallback = _kDefaultSemanticIndexCallback, this.semanticIndexOffset = 0, this.childCount, }) : super(itemBuilder, sourceList, indicatorBuilder: indicatorBuilder, gridDelegate: gridDelegate);
LoadingMoreCustomScrollView使用来创建Sliver组件,它包括了CustomScrollView的属性以及showGlowLeading/showGlowTrailing
//support for LoadingMoreSliverList class LoadingMoreCustomScrollView extends StatefulWidget { final List slivers; final Axis scrollDirection; final bool reverse; final ScrollController controller; final bool primary; final ScrollPhysics physics; final bool shrinkWrap; final double cacheExtent; final int semanticChildCount;
/// Whether to show the overscroll glow on the side with negative scroll /// offsets. final bool showGlowLeading;
/// Whether to show the overscroll glow on the side with positive scroll /// offsets. final bool showGlowTrailing;
LoadingMoreCustomScrollView({ Key key, this.scrollDirection = Axis.vertical, this.reverse = false, this.controller, this.primary, this.physics, this.shrinkWrap = false, this.cacheExtent, this.slivers = const [], this.semanticChildCount, this.showGlowLeading: true, this.showGlowTrailing: true, }) : assert(slivers != null), super(key: key);
Demo code
简单的一个Sliver
class SliverListDemo extends StatefulWidget { @override _SliverListDemoState createState() => _SliverListDemoState(); }
class _SliverListDemoState extends State { TuChongRepository listSourceRepository; @override void initState() { // TODO: implement initState listSourceRepository = new TuChongRepository(); super.initState(); }
@override void dispose() { listSourceRepository?.dispose(); // TODO: implement dispose super.dispose(); }
@override Widget build(BuildContext context) {
return Material( child: LoadingMoreCustomScrollView( slivers: [ SliverAppBar( pinned: true, title: Text(“SliverListDemo”), ), LoadingMoreSliverList( SliverListConfig( ItemBuilder.itemBuilder, listSourceRepository, //isLastOne: false )) ], ), ); } }
多个Sliver
class MultipleSliverDemo extends StatefulWidget { @override _MultipleSliverDemoState createState() => _MultipleSliverDemoState(); }
class _MultipleSliverDemoState extends State { TuChongRepository listSourceRepository; TuChongRepository listSourceRepository1;
@override void initState() { // TODO: implement initState listSourceRepository = new TuChongRepository(); listSourceRepository1 = new TuChongRepository(); super.initState(); }
@override void dispose() { listSourceRepository?.dispose(); listSourceRepository1?.dispose();
class _MultipleSliverDemoState extends State { TuChongRepository listSourceRepository; TuChongRepository listSourceRepository1;
@override void initState() { // TODO: implement initState listSourceRepository = new TuChongRepository(); listSourceRepository1 = new TuChongRepository(); super.initState(); }
@override void dispose() { listSourceRepository?.dispose(); listSourceRepository1?.dispose();
|