Flutter实现固定header底部滑动页效果示例
作者:Zuo 发布时间:2022-06-15 06:31:05
实现的效果是这样的:
刚开始的时候,是在dev上找了两个轮子,简单测了下,都不太满意,滑动事件处理的比较粗糙,总有bug。就在想着,要不要拿源码改一版的时候,让我无意间看到了这个帖子
里面的想法,大开眼界,是通过 DraggableScrollableSheet 和 IgnorePointer 来完美实现上面的效果。
实现
这是 DraggableScrollableSheet 的代码,
DraggableScrollableSheet(
maxChildSize: 0.8,
minChildSize: 0.25, // 注意都是占父组件的比例
initialChildSize: 0.25,
expand: true,
builder: (BuildContext context, ScrollController controller) {
return Stack(); // body列表和header栏都在stack内
},
)
这是 body 列表和 header,这里的 body 是个 list,
Stack(
children: [
Container(
color: Colors.blue,
child: Body( // ListView.separated
controller: controller,
paddingTop: headerHeight, // 防止压盖
),
),
const IgnorePointer( // 这里不接收事件,所以拖动 header 也能够滑动页面
child: Header( // Container[Center[Text]]
height: headerHeight,
),
),
],
)
但如果我们想在 header 内加点击事件呢?那在 Stack header 上层再加 widget 就好了。
代码就这点,我放在了 gitHub 上,感兴趣的可以看下。
2022.8.23 补充:
这是在上面功能基础上的一个小扩展,即当滑动距离超过一半则自动滚至顶部,反之回到底部,来看下效果:
思路也很简单,首先我要知道当前滚动的距离或其占比,DraggableScrollableController 提供了这个能力:
void _draggableScrollListener() {
// [_currStale] 记录下当前的占比
// [_controller.size] 即占比, 范围[minChildSize,maxChildSize]
// [_controller.pixels] 即距离
if (_currStale != _controller.size) {
_currStale = _controller.size;
}
debugPrint('[listener] size: ${_controller.size}'
', pixels : ${_controller.pixels}');
}
其次要知道用户何时停止了滚动,我们可以使用 NotificationListener 来监听 DraggableScrollableSheet 的滚动状态:
NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification notification) {
...
return false;
},
child: DraggableScrollableSheet(...),
之后在用户停止滚动的时候,我们判断当前距离,并根据结果让 DraggableScrollableSheet 自动滚动到顶部或底部。
onNotification: (ScrollNotification notification) {
if (_animation) { // 动画中,不处理状态
return false;
}
if (notification is ScrollStartNotification) {
debugPrint('start scroll');
} else if (notification is ScrollEndNotification) {
debugPrint('stop scroll');
// 通过 [_controller.animateTo] 方法滚动
_scrollAnimation();
}
return false;
在 _scrollAnimation 内就是滚动的方法了,这里要注意的是,不能直接使用 await Feature,我测试在频繁不同方向滑动时,可能会导致方法被挂起。在这直接 dedelayed(duration: xx) 即可:
Future<void> _scrollAnimation() async {
if (_animation) {
return;
}
_animation = true;
//debugPrint('async start');
final int duration;
// `await`ing the returned Feature(of [animateTo]) may cause the method to hang
// So, Start a timer to set [_animation].
if (_currStale >= (_maxScale + _minScale) * 0.5) {
duration =
(_duration * ((_maxScale - _currStale) / (_maxScale - _minScale)))
.toInt();
if (duration == 0) {
_animation = false;
return;
} else {
// [duration] control speed, Avoid situations where it's equal to 0
_animationTo(_maxScale, duration);
}
} else {
duration =
(_duration * ((_currStale - _minScale) / (_maxScale - _minScale)))
.toInt();
if (duration == 0) {
_animation = false;
return;
} else {
_animationTo(_minScale, duration);
}
}
Future.delayed(
Duration(milliseconds: duration),
).then((value) => {
//debugPrint('async stop'),
_animation = false,
});
}
其中 _animationTo
是实际控制控件滚动的方法:
void _animationTo(double scale, int duration) {
_controller.animateTo(
scale,
duration: Duration(milliseconds: duration),
curve: Curves.ease,
);
}
2022.9.24 补充:
那如果再提供一种通过点击按钮来控制 DraggableScrollableSheet
收起和弹出的方法呢?
我们可以直接这样,是不是很简单:
Future<void> _scrollAnimation2() async {
if (_animation) {
return;
}
if (_currStale > (_maxScale + _minScale) * 0.5) {
_animationTo(_minScale, _duration);
} else {
_animationTo(_maxScale, _duration);
}
}
来源:https://juejin.cn/post/7127686678587637796


猜你喜欢
- 文章来源:aspcn 作者:孙雯重复和并发服务器这个应用程序被当作一个重复的服务器.因为它只有在处理完一个进程以后才会接受另一个连接.更多的
- createCoroutine 和 startCoroutine协程到底是怎么创建和启动的?本篇文章带你揭晓。在Continuation.k
- Class:EcanRMB.cs using System; using System.Collections.Gen
- 实现HandlerInterceptor接口或者继承HandlerInterceptor的子类,比如Spring 已经提供的实现了Handl
- 首先是.select在MP查询中,默认查询所有的字段,如果有需要也可以通过select方法进行指定字段。其中要注意的细节:wrapper.s
- 前言惰性计算(尽可能延迟表达式求值)是许多函数式编程语言的特性。惰性集合在需要时提供其元素,无需预先计算它们,这带来了一些好处。首先,您可以
- 一、使用QueryByExampleExecutor1. 继承MongoRepositorypublic interface Student
- 芬兰数学家因卡拉花费3个月设计出了世界上迄今难度最大的数独游戏,而且它只有一个答案。因卡拉说只有思考能力最快、头脑最聪明的人才能破解这个游戏
- 本文实例讲述了Android非XML形式动态生成、调用页面的方法。分享给大家供大家参考。具体分析如下:这个问题是这样的:我们不使用XML构建
- 问题背景实际项目碰到一个上游服务商接口有10秒的查询限制(同个账号)。项目中有一个需求是要实时统计一些数据,一个应用下可能有多个相同的账号。
- 项目需求最近项目中有一个需求就是让Java代码去代替人工操作,自动生成PPT,具体就是查询数据库数据,然后根据模板文件(PPT),将数据库数
- 安装配置完Java的jdk,下面就开始写第一个java程序--hello World.用来在控制台输出“Hello World”。首先,我们
- 做侧滑删除网上有很多方案,比如重写Listview实现滑动的监听,今天说下一个SwipeListView,这个是之前一个朋友在网上开源的一个
- 觉得好有点帮助就顶一下啦。socke编程,支持多客户端,多线程操作避免界面卡死。开启socketprivate void button1_C
- 本文将用两个方法来写类似汽车荷载的进度用LinearLayout的addview方法加上for循环用自定义控件的方法先上截图1. 用Line
- Android用SharedPreferences实现登录注册注销功能前言本文用SharedPreferences本地缓存账号信息来实现登录
- 之前文章介绍过了Fluent基本框架等,其中有几个重要的方法用到了IQuery和IUpdate对象。 这2个对象是FluentMybatis
- Android 中下拉菜单,即如html中的<select>,关键在于调用setDropDownViewResource方法,以
- 首先引入pom <!--SpringBoot 2.1.0--> <parent>  
- 前言在 App 开发过程中,ListView 是 比较很常见的控件,用来处理 列表类的数据展示。当然 Flutter 也是支持的,由于 Fl