Open iAllenC opened 3 years ago
作者的这个库不支持这种方式,还有一个比较常用的flutter的刷新库flutter_easyrefresh.和作者的实现思路一样,都是用customScrollView包裹住咱们的布局,然后在头部insert一个header,底部add一个footer. 所以这两个刷新库,天然就不支持包裹NestScrollView. 如果想实现你的这个业务,有两个思路: 1.还使用这些第三方的刷新库,你自己的布局用CustomScrollView,然后自己定义ScrollPositon和ScrollController.这种方式稍微复杂一些,可以参考一下美团外卖的那个demo. 我使用的是flutter_easyrefresh这个库,在模拟NestedScrollView实现了自定义的scrollPositon后,实现了和NestedScrollView相似的滑动模式.但是嵌套入下拉刷新库内会出现一些滑动bug,目前还没找到好的解决方案.
2.自己做一个刷新控件,可以包裹NestScrollView,通过外层包裹ScrollNotification然后监听滑动在顶部还是底部.目前正在看这些刷新库的源码实现. @peng8350 作者看一下我说的对不对
需求:如同咸鱼首页(推荐那个页) 1.整个页面支持下拉刷新,上拉加载更多.(下拉上拉时,整个页面一起滑动) 2.整个页面中含有以下内容模块(纵向排列): 横向列表(固定数量),轮播图,可以跟随滑动并吸顶的TabBar,与TabBar绑定的TabBarView. 3.实现思路.我目前的实现思路有两种
第一种思路: A:使用第三方刷新库(flutter_easyrefresh/pull_to_refresh)为最外层布局 自己的业务布局使用CustomScrollView 横向列表(固定数量)和轮播图使用SliverList包裹. 可以跟随滑动并吸顶的TabBar使用SliverPersistentHeader 与TabBar绑定的TabBarView使用SliverFillRemaining包裹. 问题就出现在这个TabBarView, 我之前的想法是TabBarView里的每一个Page中会用到ListView,我把这些ListView设置成shrinkWrap为True,然后physics设置成NeverScrollableScrollPhysics.(想禁用掉ListView自己的滑动并且充满父布局). 如上操作之后,使用SliverFillRemaining包裹后,SliverFillRemaining里的TabBarView并没有被ListView撑满,整个SliverFillRemaing的布局高度始终是一个固定的数值.
第二种思路: 自己的业务布局使用NestedScrollView 横向列表(固定数量)和轮播图使用SliverList包裹. 可以跟随滑动并吸顶的TabBar使用SliverPersistentHeader. 将以上两个子布局放入NestedScrollView的headerSliverBuilder中,将TabBarView放入NestedScrollView的body中. 不禁用TabBarView中ListView的滚动. 这样整个页面滑动起来不会有问题. 问题出现在 将以上的NestedScrollView放入第三方刷新库(flutter_easyrefresh/pull_to_refresh)中后会出现问题.看了一下第三方库的源码,是把业务布局放入CustomScrollView中实现的.但是NestedScrollView无法作为一个sliver插入到CustomScrollView中.导致无法下拉刷新加载更多. 综上,想请教一下咸鱼这个页面的布局实现思路是怎样的.期待回复!感谢!
@houziruinb87 请问你解决了你说的这个问题了吗 我遇到了和你差不多的问题
结构是SmartRefresher--NestedScrollView->SliverAppBar+TabBarView->GridView。 页面显示没有问题,但是滑动的时候无法显示下拉刷新 把刷新放到GridView上可以解决,但是因为SliverAppBar上的部分内容也是跟随刷新的,所以这个下拉刷新还是希望能放到外面来。不知道是我的用法不对还是怎样?代码如下:
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart';
class NestedPageRoute extends StatefulWidget { @override State createState() { return _NestedPageState(); } }
class _NestedPageState extends State with SingleTickerProviderStateMixin { RefreshController _refreshController = RefreshController(initialRefresh: true); ScrollController _scrollviewController = ScrollController(); TabController? _tabController;
@override void initState() { // TODO: implement initState super.initState(); _tabController = TabController(length: 4, vsync: this); }
Widget _buildFooter() { return CustomFooter(builder: (BuildContext context, LoadStatus? mode) { Widget body; if (mode == LoadStatus.idle) { body = Text("上拉加载"); } else if (mode == LoadStatus.loading) { body = CupertinoActivityIndicator(); } else if (mode == LoadStatus.failed) { body = Text("加载失败!点击重试!"); } else if (mode == LoadStatus.canLoading) { body = Text("松手,加载更多!"); } else { body = Text("没有更多数据了!"); } return Container( height: 55.0, child: Center(child: body), ); }); }
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("Title"),), body: SmartRefresher( controller: _refreshController, scrollController: _scrollviewController, enablePullDown: true, enablePullUp: true, header: WaterDropHeader( refresh: CupertinoActivityIndicator(), ), footer: _buildFooter(), onRefresh: _onRefresh, onLoading: _onLoading, child: NestedScrollView( controller: _scrollviewController, headerSliverBuilder: (context, boxIsScrolled) { return [ SliverAppBar( pinned: true, floating: true, elevation: 0.5, forceElevated: true, //backgroundColor: Colors.grey, expandedHeight: 240, flexibleSpace: FlexibleSpaceBar( collapseMode: CollapseMode.pin, //视差效果 background: Container( //color: Colors.grey, child: Column( children: [ Container( height: 190, color: Colors.blue, ) ], ), ), ), bottom: TabBar(controller: _tabController, tabs: [ Tab( text: "首页", ), Tab( text: "消息", ), Tab( text: "购物", ), Tab( text: "我的", ) ]), ), ]; }, body: TabBarView(controller: _tabController, children: [ ListView.builder(itemBuilder: (context, index) { return Center( child: Text(index.toString()), ); }, itemCount: 50,shrinkWrap: true, physics: NeverScrollableScrollPhysics(),), Center( child: Text("two"), ), Center( child: Text("three"), ), Center( child: Text("four"), ), ])), ) ); }
void _onRefresh() async { await Future.delayed(Duration(seconds: 2)); _refreshController.refreshCompleted(); setState(() {}); }
void _onLoading() async { await Future.delayed(Duration(seconds: 2)); _refreshController.loadComplete(); setState(() {}); }
}
请问解决了吗?
qingen
class NestedPageRoute extends StatefulWidget { @override State createState() { return _NestedPageState(); } }
class _NestedPageState extends State with SingleTickerProviderStateMixin { refresh.RefreshController _refreshController = refresh.RefreshController(initialRefresh: true); ScrollController _scrollviewController = ScrollController(); TabController _tabController;
@override void initState() { super.initState(); _tabController = TabController(length: 4, vsync: this); } List list1 = [1,2,3,4,5,6,7,8,9,]; @override Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Title"),
),
body: RefreshIndicator(
notificationPredicate: (notifation) {
// 返回true即可
return true;
},
onRefresh: () {
return Future.delayed(Duration(seconds: 2), () {
print("我是调用的外部刷新0");
return true;
});
},
child: NestedScrollView(
controller: _scrollviewController,
headerSliverBuilder: (context, boxIsScrolled) {
return [
SliverAppBar(
pinned: true,
floating: true,
elevation: 0.5,
forceElevated: true,
expandedHeight: 240,
flexibleSpace: FlexibleSpaceBar(
collapseMode: CollapseMode.pin, //视差效果
background: Container(
child: Column(
children: [
Container(
height: 190,
color: Colors.blue,
)
],
),
),
),
bottom: TabBar(controller: _tabController, tabs: [
Tab(
text: "首页",
),
Tab(
text: "消息",
),
Tab(
text: "购物",
),
Tab(
text: "我的",
)
]),
),
];
},
body: TabBarView(controller: _tabController, children: [
refresh.SmartRefresher(
controller: _refreshController,
onRefresh: _onRefresh,
onLoading: _onLoading,
enablePullDown: false,
enablePullUp: true,
child: ListView.builder(
itemBuilder: (context, index) {
return Center(
child: Text(list1[index].toString()),
);
},
itemCount: list1.length,
// shrinkWrap: true,
// physics: NeverScrollableScrollPhysics(),
),
),
Center(
child: Text("two"),
),
Center(
child: Text("three"),
),
Center(
child: Text("four"),
),
]))),
// )
);
}
void _onRefresh() async { await Future.delayed(Duration(seconds: 2)); _refreshController.refreshCompleted(); setState(() { print("我是调用的内部刷新1"); }); }
void _onLoading() async { await Future.delayed(Duration(seconds: 2)); setState(() { List list2 = [10,11,12,13,14,15,16,17,18,19,20]; list1.addAll(list2); print("我是调用的内部加载1"); }); _refreshController.loadComplete(); } }
试试吧 也许是你要的效果
需求:如同咸鱼首页(推荐那个页) 1.整个页面支持下拉刷新,上拉加载更多.(下拉上拉时,整个页面一起滑动) 2.整个页面中含有以下内容模块(纵向排列): 横向列表(固定数量),轮播图,可以跟随滑动并吸顶的TabBar,与TabBar绑定的TabBarView. 3.实现思路.我目前的实现思路有两种
第一种思路: A:使用第三方刷新库(flutter_easyrefresh/pull_to_refresh)为最外层布局 自己的业务布局使用CustomScrollView 横向列表(固定数量)和轮播图使用SliverList包裹. 可以跟随滑动并吸顶的TabBar使用SliverPersistentHeader 与TabBar绑定的TabBarView使用SliverFillRemaining包裹. 问题就出现在这个TabBarView, 我之前的想法是TabBarView里的每一个Page中会用到ListView,我把这些ListView设置成shrinkWrap为True,然后physics设置成NeverScrollableScrollPhysics.(想禁用掉ListView自己的滑动并且充满父布局). 如上操作之后,使用SliverFillRemaining包裹后,SliverFillRemaining里的TabBarView并没有被ListView撑满,整个SliverFillRemaing的布局高度始终是一个固定的数值.
第二种思路: 自己的业务布局使用NestedScrollView 横向列表(固定数量)和轮播图使用SliverList包裹. 可以跟随滑动并吸顶的TabBar使用SliverPersistentHeader. 将以上两个子布局放入NestedScrollView的headerSliverBuilder中,将TabBarView放入NestedScrollView的body中. 不禁用TabBarView中ListView的滚动. 这样整个页面滑动起来不会有问题. 问题出现在 将以上的NestedScrollView放入第三方刷新库(flutter_easyrefresh/pull_to_refresh)中后会出现问题.看了一下第三方库的源码,是把业务布局放入CustomScrollView中实现的.但是NestedScrollView无法作为一个sliver插入到CustomScrollView中.导致无法下拉刷新加载更多. 综上,想请教一下咸鱼这个页面的布局实现思路是怎样的.期待回复!感谢!
这两种思路我都尝试过,基本和你想的差不多,都没法满足需求。 第一种思路:SliverFillRemaining 可以理解为Expanded一个ScrollView高度,ListView禁滑后,底下部分内容无法查看,可视窗口就是Expanded的高度。这样可以下拉刷新。 第二种思路:使用NestedScrollView滑动没有问题,不能下拉刷新,即使我给NestedScrollView添加了header。感觉ListView区域的滑动只是通过controller设置给NestedScrollView,不能触发下拉刷新。 需要实现这种效果,可能要自定义NestedScrollView代码了。
结构是SmartRefresher--NestedScrollView->SliverAppBar+TabBarView->GridView。 页面显示没有问题,但是滑动的时候无法显示下拉刷新 把刷新放到GridView上可以解决,但是因为SliverAppBar上的部分内容也是跟随刷新的,所以这个下拉刷新还是希望能放到外面来。不知道是我的用法不对还是怎样?代码如下:
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart';
class NestedPageRoute extends StatefulWidget { @override State createState() {
return _NestedPageState();
}
}
class _NestedPageState extends State
with SingleTickerProviderStateMixin {
RefreshController _refreshController = RefreshController(initialRefresh: true);
ScrollController _scrollviewController = ScrollController();
TabController? _tabController;
@override void initState() { // TODO: implement initState super.initState(); _tabController = TabController(length: 4, vsync: this); }
Widget _buildFooter() { return CustomFooter(builder: (BuildContext context, LoadStatus? mode) { Widget body; if (mode == LoadStatus.idle) { body = Text("上拉加载"); } else if (mode == LoadStatus.loading) { body = CupertinoActivityIndicator(); } else if (mode == LoadStatus.failed) { body = Text("加载失败!点击重试!"); } else if (mode == LoadStatus.canLoading) { body = Text("松手,加载更多!"); } else { body = Text("没有更多数据了!"); } return Container( height: 55.0, child: Center(child: body), ); }); }
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("Title"),), body: SmartRefresher( controller: _refreshController, scrollController: _scrollviewController, enablePullDown: true, enablePullUp: true, header: WaterDropHeader( refresh: CupertinoActivityIndicator(), ), footer: _buildFooter(), onRefresh: _onRefresh, onLoading: _onLoading, child: NestedScrollView( controller: _scrollviewController, headerSliverBuilder: (context, boxIsScrolled) { return [ SliverAppBar( pinned: true, floating: true, elevation: 0.5, forceElevated: true, //backgroundColor: Colors.grey, expandedHeight: 240, flexibleSpace: FlexibleSpaceBar( collapseMode: CollapseMode.pin, //视差效果 background: Container( //color: Colors.grey, child: Column( children:[
Container(
height: 190,
color: Colors.blue,
)
],
),
),
),
bottom: TabBar(controller: _tabController, tabs: [
Tab(
text: "首页",
),
Tab(
text: "消息",
),
Tab(
text: "购物",
),
Tab(
text: "我的",
)
]),
),
];
},
body: TabBarView(controller: _tabController, children: [
ListView.builder(itemBuilder: (context, index) {
return Center(
child: Text(index.toString()),
);
}, itemCount: 50,shrinkWrap: true, physics: NeverScrollableScrollPhysics(),),
Center(
child: Text("two"),
),
Center(
child: Text("three"),
),
Center(
child: Text("four"),
),
])),
)
);
}
void _onRefresh() async { await Future.delayed(Duration(seconds: 2)); _refreshController.refreshCompleted(); setState(() {}); }
void _onLoading() async { await Future.delayed(Duration(seconds: 2)); _refreshController.loadComplete(); setState(() {}); }
}