文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Flutter BottomSheet 三段式拖拽

2023-09-21 19:19

关注

BottomSheetBehavior


前面倒是有讲过Android原生的BottomSheetBehavior,使用场景还是蛮多的,最近在用Flutter做一款地图App,有用到BottomSheet的功能,但是 Flutter 自带的BottomSheet有点拉,只能显示和隐藏销毁,不支持折叠为最小高度状态也不支持三段式拖动,那就自己撸一个吧:

追踪 BottomSheet

既然是基于系统的BottomSheet ,不妨来看看sdk的实现方式,正常来讲,显示一个BottomSheet,可以通过showBottomSheet 来触发,或者给Scaffold配置bottomSheet属性,查看源码可以看到Scaffold.of(context).showBottomSheet,内部是创建了一个_StandardBottomSheet,继续追踪发现Widget其实是通过AnimatedBuilder来实现内容高度的扩展,其内部维护了一个BottomSheet。

简单阅读下BottomSheet源码,重点就在于 GestureDetector 的垂直方向上的手势回调 onVerticalDragUpdate 、以及onVerticalDragEnd,拖动位置更新、惯性滑动以及销毁,核心都在这了。
在这里插入图片描述

系统默认实现效果

保留这一份默认效果,对于想使用默认效果的同学,不做任何额外配置即可。

在这里插入图片描述

准备要实现的功能点:

  1. 三段式: 基于SDK的BottomSheet ,可扩展为完全展开、中间状态、折叠状态;
  2. 阻尼、惯性滑动: 支持配置最小滑动偏移量;
  3. 保持状态,支持Peek状态: 以最小高度显示BottomSheet;
  4. 打破 showBottomSheet 限制: 兼容系统默认的弹出方式,亦可当作正常的Widget使用,脱离showBottomSheet。

定义三段式状态:BottomSheetBehavoir

开启三段式,我们还需要配置一个约束条件,即BottomSheet的最大高度和最小高度 BoxConstraints:

var peekThreshold = enableHalf     ? min(_childHeight / 2, constraints.minHeight) / _childHeight     : constraints.minHeight / _childHeight;

阀值定义

当拖拽结束时,如果拖拽偏移量小于此阀值,则恢复状态,这里有个麻烦的点是需要根据用户拖拽方向来判断,是向上还是向下拖动。
方向判断可以在 _handleDragStart 回调时记录初始偏移量startY,_handleDragEnd 时计算开始和结束的差值

/// 偏移量var offset = updateY-startY ;/// 当前动画值 var value = widget.animationController!.value; late double toValue; late BottomSheetBehavior mode;

offset<0 为向上滑动,反之 向下滑动。接下来需要根据滚动阀值来更新BottomSheet状态。

1. 未达到滚动阀值,恢复状态

if (value >= _maxThreshold) {   // 处于Expand状态,恢复   toValue = _maxThreshold;   mode = BottomSheetBehavior.EXPANDED; } else if (value > _halfThreshold && enableHalf) {   // 处于Half,恢复   toValue = _halfThreshold;   mode = BottomSheetBehavior.HALF; } else {   toValue = peekThreshold;   mode = BottomSheetBehavior.PEEK; }
if (value > _halfThreshold) {   // 处于Expand状态,恢复   toValue = _maxThreshold;   mode = BottomSheetBehavior.EXPANDED; } else if (value > peekThreshold && enableHalf) {   // 处于Half,恢复   toValue = _halfThreshold;   mode = BottomSheetBehavior.HALF; } else {   toValue = peekThreshold;   mode = BottomSheetBehavior.PEEK; }

2. 达到滚动阀值,更新状态

if (value > _halfThreshold) {   toValue = _maxThreshold;   mode = BottomSheetBehavior.EXPANDED; } else if (value > peekThreshold) {   toValue = enableHalf ? _halfThreshold : _maxThreshold;   mode = enableHalf ? BottomSheetBehavior.HALF : BottomSheetBehavior.EXPANDED; } else {   toValue = peekThreshold;   mode = BottomSheetBehavior.PEEK; }
if (value > _halfThreshold) {  toValue = enableHalf ? _halfThreshold : peekThreshold;  mode = enableHalf ? BottomSheetBehavior.HALF : BottomSheetBehavior.PEEK;} else {  toValue = peekThreshold;  mode = BottomSheetBehavior.PEEK;}

以上,我们获取到了开始讲到的AnimatedBuilder的 动画值以及变化量,在**_handleDragEnd**中可以通过animateTo平滑的过渡BottomSheet状态

/// 以动画的形式flyvoid animateTo(double to) {  widget.animationController!.animateTo(    to,    curve: Curves.linearToEaseOut,    duration: animateDuration,  );}
Future.delayed(animateDuration, () => widget.onBehaviorChanged?.call(mode));

至此,既保留了flutter默认的BottomSheet效果,又扩展了三段式,当然,调用方式和系统BottomSheet一模一样,另外还可以像普通Widget一样来使用哦*
Just Do It :

bottom_sheet_plus: ^0.0.1

来看看最终的效果吧

项目效果

Demo

来源地址:https://blog.csdn.net/sxt_zls/article/details/132206417

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯