文章目录

  • 一、明确需求
  • 二、实现需求
    • 1. 滑动菜单实现使用`SingleChildScrollView`:
    • 2. 列表滑动不够距离则菜单再次隐藏,距离足够则完全展示菜单。
    • 3. 菜单支持事件处理。
    • 4. 菜单样式、个数由使用者传入。
    • 5. 除菜单之外部分点击,如其他列表或本列表非菜单部分,则菜单隐藏

网上浏览Flutter教程的时候,找到一篇文章, Flutter | 超简单仿微信QQ侧滑菜单组件,研读了全文之后,感觉作者思路清晰,教程简洁明了,忍不住自己实现了一下。源码见 Github

和微信的菜单对比,原文中有一点没有实现:

  • 菜单与其他列表没有联动,如其他列表点击后,菜单没有收回,原因是作者提供的是侧滑菜单组件,而不是将整个列表做为一个组件提供。

添加这个功能后,先看一下最终实现的效果:

一、明确需求

  1. 列表可以滑动出菜单;
  2. 列表滑动不够距离则菜单再次隐藏,距离足够则完全展示菜单;
  3. 菜单支持事件处理
  4. 菜单样式、个数由使用者传入;
  5. 除菜单之外部分点击,如其他列表或本列表非菜单部分,则菜单隐藏;

前面几点原文都有讲解,不过因为这里尝试自己去写,有些点不太一样。

二、实现需求

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. 菜单样式、个数由使用者传入。

这两个一起说明,传入的菜单其实没有太多特殊处理,只是用SingleChildScrollViewRow包裹了一下,在传入的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侧滑菜单组件(改)相关推荐

  1. iOS仿QQ侧滑菜单、登录按钮动画、仿斗鱼直播APP、城市选择器、自动布局等源码

    iOS精选源码 QQ侧滑菜单,右滑菜单,QQ展开菜单,QQ好友分组 image 登录按钮 image 3分钟快捷创建高性能轮播图 ScrollView嵌套ScrolloView(UITableView ...

  2. iOS仿QQ侧滑菜单、登录按钮动画、仿斗鱼直播APP、城市选择器、自动布局等源码...

    iOS精选源码 QQ侧滑菜单,右滑菜单,QQ展开菜单,QQ好友分组 登录按钮 3分钟快捷创建高性能轮播图 ScrollView嵌套ScrolloView(UITableView .UICollecti ...

  3. 仿QQ侧滑菜单(二)

    在(一)https://blog.csdn.net/qq_36551426/article/details/80427352中讲了一下DrawerLayout的简单概念,但是这并不足以让我们去做一个完 ...

  4. Android仿QQ侧滑菜单

    先上效果图: GIF图有点模糊,源码已上传Github:Android仿QQ侧滑菜单 ####整体思路: 自定义ItemView的根布局(SwipeMenuLayout extends LinearL ...

  5. Android高仿QQ侧滑菜单

    文章目录 效果图 整体思路 实现过程 先分析SwipeMenuLayout 再分析下SwipeRecycleView 踩过的坑 后记 效果图 GIF图有点模糊,源码已上传Github:Android仿 ...

  6. Android 仿QQ侧滑菜单

    前言 集成方式 兼容超强的BaseRecyclerViewAdapterHelper 方法及属性介绍 THANKS 侧滑的雏形 测绘布局 onLayout onMeasure MotionEvent事 ...

  7. 超简单仿QQ步数显示控件

    本着写文即学习的态度,记录下自定义一款超简单仿QQ步数加载控件,话不多数先看图. 一,特性: 1,外圈大圆.进度圆和数字显示的颜色均可以自定义 2,设置最大值和当前值 3,设置加载持续时间 二,实现: ...

  8. android 仿微信头像裁剪,Android仿微信QQ设置图形头像裁剪功能

    最近在做毕业设计,想有一个功能和QQ一样可以裁剪头像并设置圆形头像,额,这是设计狮的一种潮流. 而纵观现在主流的APP,只要有用户系统这个功能,这个需求一般都是在(bu)劫(de)难(bu)逃(xue ...

  9. QQ侧滑菜单的实现和拓展-DrawerLayout

    1,不多废话,直接来效果图如下: 拓展 如上图我们可以看出图一和QQ侧滑菜单基本一样.图二进行了水平和竖直方向上的缩放. 2,DrawerLayout来实现这些效果 首先我相信很多人都用过v4包里面的 ...

最新文章

  1. 如何消费WCF Data Services定义的服务操作
  2. Java 使用匿名内部类在方法内部定义并启动线程
  3. [刘阳Java]_Web前端入门级练习_迅雷官宣网设计
  4. submit()提交表单时,显示警示框
  5. SAP Spartacus 中 Angular json pipe 的工作原理
  6. Linux操作系统六大优点
  7. 怎么快速写python自动化脚本_自动化脚本如何编写?
  8. linux 发送http请求方式
  9. mysql like n_MySQL LIKE 子句
  10. php代码输出sql语句,教你在Laravel中轻松容易的输出完整的SQL语句
  11. ant design pro(二)布局
  12. matlab在机器视觉的应用实例,十个基于机器视觉的实用案例介绍
  13. Springboot——quartz简单配置和使用
  14. Linux 镜像文件ISO下载地址、centos网络配置:
  15. 数据分析必备软件Excel安装包+激活工具
  16. PR常见问题:pr导入素材没有音轨怎么办
  17. 给自己的Web站点嵌入一个免费的图片编辑器
  18. nginx uwsgi django部署
  19. toft 测试用例rat_TD-LTE终端测试规范——通信功能和性能分册(上).pdf
  20. 7个跑步易犯的错误和解决办法

热门文章

  1. Git从安装到大师,最全的使用攻略
  2. matlab rs232 fpga,RS232接口的FPGA程序设计(VHDL)
  3. 运动学模型(一)-----传感器选型与技术路线
  4. 差分方程c语言,filter函数 C语言差分方程
  5. 会议报道丨心语心“悦”——抑郁症诊疗进展“大咖”谈(三)
  6. reactJs/js微信分享教程简单实用版
  7. 因疫情冲击实体企业被迫关门停业,浑然不知同行已经转型升级了?
  8. TYPE-C口是怎么样的接口?它有什么功能强大的地方?
  9. SAP ABAP 业务对象 BUS1113 CostElementGroup 成本要素组 BAPI 清单和相关 TCODE
  10. python练习实例——芯片测试