Flutter | 超简单仿微信QQ侧滑菜单组件(改)
文章目录
- 一、明确需求
- 二、实现需求
- 1. 滑动菜单实现使用`SingleChildScrollView`:
- 2. 列表滑动不够距离则菜单再次隐藏,距离足够则完全展示菜单。
- 3. 菜单支持事件处理。
- 4. 菜单样式、个数由使用者传入。
- 5. 除菜单之外部分点击,如其他列表或本列表非菜单部分,则菜单隐藏
网上浏览Flutter教程的时候,找到一篇文章, Flutter | 超简单仿微信QQ侧滑菜单组件,研读了全文之后,感觉作者思路清晰,教程简洁明了,忍不住自己实现了一下。源码见 Github
和微信的菜单对比,原文中有一点没有实现:
- 菜单与其他列表没有联动,如其他列表点击后,菜单没有收回,原因是作者提供的是侧滑菜单组件,而不是将整个列表做为一个组件提供。
添加这个功能后,先看一下最终实现的效果:
一、明确需求
- 列表可以滑动出菜单;
- 列表滑动不够距离则菜单再次隐藏,距离足够则完全展示菜单;
- 菜单支持事件处理
- 菜单样式、个数由使用者传入;
- 除菜单之外部分点击,如其他列表或本列表非菜单部分,则菜单隐藏;
前面几点原文都有讲解,不过因为这里尝试自己去写,有些点不太一样。
二、实现需求
1. 滑动菜单实现使用SingleChildScrollView
:
SingleChildScrollView(scrollDirection:Axis.horizontal,//横向滚动controller: controller,child: IntrinsicHeight(child: Row(children: _buildChildren(context),),),
),
可以看到中间使用了一个IntrinsicHeight
,这个类可以保证Row中的Container菜单自动适应和列表同一个高度,如下图是使用与不使用这个widget的差别:
2. 列表滑动不够距离则菜单再次隐藏,距离足够则完全展示菜单。
这个原文中也有讲解,使用Listener这个Widget,onPointerUp来监听原始指针事件的抬起手势,无论是滑动后抬起还是直接抬起,都可以监听,而不会因手势冲突而收不到事件,详细可以参考:8.1 原始指针事件处理。
Listener(
onPointerUp: (upEvent){if(isAnimated) return;//后面再说明if(controller.offset < menuWidth / 5){//不足菜单5分之1,弹回controller.animateTo(0, duration: Duration(milliseconds: 100), curve: Curves.linear);}else{//否则直接展示所有菜单controller.animateTo(menuWidth, duration: Duration(milliseconds: 100), curve: Curves.linear);}
},
3. 菜单支持事件处理。
4. 菜单样式、个数由使用者传入。
这两个一起说明,传入的菜单其实没有太多特殊处理,只是用SingleChildScrollView
和Row
包裹了一下,在传入的child的后面添加了菜单项,所有事件和样式、个数等还是由使用者直接传入。
_buildChildren(BuildContext context){var screenSize = MediaQuery.of(context).size;List<Widget> childrenWidget = List<Widget>();childrenWidget.add(Container(width: screenSize.width,child: child,));childrenWidget.addAll(menus.map((e)=>Container(child: e,)));return childrenWidget;
}
5. 除菜单之外部分点击,如其他列表或本列表非菜单部分,则菜单隐藏
实现这个需求,其实只要在整个列表上添加一个“按下”事件的监听,如果点击位置不在菜单范围内,则菜单隐藏即可。使用Listener Widget可以完美实现,按下事件的回调可以取到按下的位置。同时,为了在子节点中取到这个“按下位置”,因为没有将控件强关联,所以使用了InheritedWidget,进行数据传递,详见:7.2 数据共享(InheritedWidget)。
class _SlideMenuState extends State<SlideMenu> {Offset tapDownOffset;@overrideWidget build(BuildContext context) {return ToggleMenuData(tapDownOffset: tapDownOffset,child: Listener(onPointerDown: (downEvent){setState(() {tapDownOffset = downEvent.position;});},child: ListView.builder(itemCount: widget.itemCount, itemBuilder: widget.builder),));}
}class ToggleMenuData extends InheritedWidget {final Offset tapDownOffset;ToggleMenuData({@required this.tapDownOffset, Widget child}): super(child: child);static ToggleMenuData of(BuildContext context) {return context.inheritFromWidgetOfExactType(ToggleMenuData);}@overridebool updateShouldNotify(ToggleMenuData oldWidget) {return oldWidget.tapDownOffset != tapDownOffset;}
}
然后在子节点中,判断点击位置是否是菜单范围内,不在范围内则隐藏菜单。有两个细节:
- 一个是
ScrollController
在build时,还未与SingleChildScrollView
关联,无法取到偏移量,需要使用WidgetsBinding.instance.addPostFrameCallback
添加回调:
WidgetsBinding.instance.addPostFrameCallback((duration) {Offset tapDownOffset = ToggleMenuData.of(context).tapDownOffset;if (tapDownOffset != null && controller.hasClients) {RenderBox renderBox = context.findRenderObject();Offset myOffset = renderBox.localToGlobal(Offset(0, 0));Size mySize = renderBox.size;//菜单点击位置不在按钮范围内if (controller.offset > 0 &&(screenSize.width - controller.offset > tapDownOffset.dx ||myOffset.dy > tapDownOffset.dy ||myOffset.dy + mySize.height < tapDownOffset.dy)) {isAnimated = true;controller.animateTo(0,duration: Duration(milliseconds: 100), curve: Curves.linear).then((v) {isAnimated = false;});}}
});
- 还有一个是子节点的
onPointerUp
事件会在父节点的onPointerDown
事件后触发,这样如果点击在菜单左侧区域,如下图:
则会先触发父节点的onPointerDown
事件,将菜单隐藏,再触发子节点的onPointerUp
事件,想将菜单展示,发生冲突,所以需要加一个判断,父节点动画未结束时,子结点事件不处理,即保留点击上图红色区域内则菜单隐藏的逻辑。
onPointerUp: (upEvent) {//如果已在动画中,不处理if (isAnimated) return;if (controller.offset < menuWidth / 5) {//不足菜单5分之1,弹回controller.animateTo(0,duration: Duration(milliseconds: 100), curve: Curves.linear);} else {//否则直接展示所有菜单controller.animateTo(menuWidth,duration: Duration(milliseconds: 100), curve: Curves.linear);}
},
所有源码见Github
Flutter | 超简单仿微信QQ侧滑菜单组件(改)相关推荐
- iOS仿QQ侧滑菜单、登录按钮动画、仿斗鱼直播APP、城市选择器、自动布局等源码
iOS精选源码 QQ侧滑菜单,右滑菜单,QQ展开菜单,QQ好友分组 image 登录按钮 image 3分钟快捷创建高性能轮播图 ScrollView嵌套ScrolloView(UITableView ...
- iOS仿QQ侧滑菜单、登录按钮动画、仿斗鱼直播APP、城市选择器、自动布局等源码...
iOS精选源码 QQ侧滑菜单,右滑菜单,QQ展开菜单,QQ好友分组 登录按钮 3分钟快捷创建高性能轮播图 ScrollView嵌套ScrolloView(UITableView .UICollecti ...
- 仿QQ侧滑菜单(二)
在(一)https://blog.csdn.net/qq_36551426/article/details/80427352中讲了一下DrawerLayout的简单概念,但是这并不足以让我们去做一个完 ...
- Android仿QQ侧滑菜单
先上效果图: GIF图有点模糊,源码已上传Github:Android仿QQ侧滑菜单 ####整体思路: 自定义ItemView的根布局(SwipeMenuLayout extends LinearL ...
- Android高仿QQ侧滑菜单
文章目录 效果图 整体思路 实现过程 先分析SwipeMenuLayout 再分析下SwipeRecycleView 踩过的坑 后记 效果图 GIF图有点模糊,源码已上传Github:Android仿 ...
- Android 仿QQ侧滑菜单
前言 集成方式 兼容超强的BaseRecyclerViewAdapterHelper 方法及属性介绍 THANKS 侧滑的雏形 测绘布局 onLayout onMeasure MotionEvent事 ...
- 超简单仿QQ步数显示控件
本着写文即学习的态度,记录下自定义一款超简单仿QQ步数加载控件,话不多数先看图. 一,特性: 1,外圈大圆.进度圆和数字显示的颜色均可以自定义 2,设置最大值和当前值 3,设置加载持续时间 二,实现: ...
- android 仿微信头像裁剪,Android仿微信QQ设置图形头像裁剪功能
最近在做毕业设计,想有一个功能和QQ一样可以裁剪头像并设置圆形头像,额,这是设计狮的一种潮流. 而纵观现在主流的APP,只要有用户系统这个功能,这个需求一般都是在(bu)劫(de)难(bu)逃(xue ...
- QQ侧滑菜单的实现和拓展-DrawerLayout
1,不多废话,直接来效果图如下: 拓展 如上图我们可以看出图一和QQ侧滑菜单基本一样.图二进行了水平和竖直方向上的缩放. 2,DrawerLayout来实现这些效果 首先我相信很多人都用过v4包里面的 ...
最新文章
- 如何消费WCF Data Services定义的服务操作
- Java 使用匿名内部类在方法内部定义并启动线程
- [刘阳Java]_Web前端入门级练习_迅雷官宣网设计
- submit()提交表单时,显示警示框
- SAP Spartacus 中 Angular json pipe 的工作原理
- Linux操作系统六大优点
- 怎么快速写python自动化脚本_自动化脚本如何编写?
- linux 发送http请求方式
- mysql like n_MySQL LIKE 子句
- php代码输出sql语句,教你在Laravel中轻松容易的输出完整的SQL语句
- ant design pro(二)布局
- matlab在机器视觉的应用实例,十个基于机器视觉的实用案例介绍
- Springboot——quartz简单配置和使用
- Linux 镜像文件ISO下载地址、centos网络配置:
- 数据分析必备软件Excel安装包+激活工具
- PR常见问题:pr导入素材没有音轨怎么办
- 给自己的Web站点嵌入一个免费的图片编辑器
- nginx uwsgi django部署
- toft 测试用例rat_TD-LTE终端测试规范——通信功能和性能分册(上).pdf
- 7个跑步易犯的错误和解决办法
热门文章
- Git从安装到大师,最全的使用攻略
- matlab rs232 fpga,RS232接口的FPGA程序设计(VHDL)
- 运动学模型(一)-----传感器选型与技术路线
- 差分方程c语言,filter函数 C语言差分方程
- 会议报道丨心语心“悦”——抑郁症诊疗进展“大咖”谈(三)
- reactJs/js微信分享教程简单实用版
- 因疫情冲击实体企业被迫关门停业,浑然不知同行已经转型升级了?
- TYPE-C口是怎么样的接口?它有什么功能强大的地方?
- SAP ABAP 业务对象 BUS1113 CostElementGroup 成本要素组 BAPI 清单和相关 TCODE
- python练习实例——芯片测试