Android 触摸事件的研究与应用

移动时代 Android app 开发必备技能

博文封面

Android 触摸事件的研究与应用

背景

三年前(2016 年)由于公司项目中涉及到一个仿 iOS 系统列表控件列表项的侧滑菜单 UI 交互效果(这个 UI 交互效果竟然 iOS 系统自带,苦逼的 Android 程序员啊。。。),尽管当时有 Android 端现有的轮子可用(SwipeMenuListView),但是出于以下两点原因我只能自造轮子:

  • 当时 Android 项目列表控件已经全部迁移至 RecyclerView ,一个强大到不行的谷歌官方支持库用于替代系统 SDK 自带的复杂、难以扩展、老态龙钟的 ListView 的地位,没有现有好用的 RecyclerView 侧滑菜单轮子可用,也许当时根本就没有(当时并没有找到),2015 年谷歌发布了 Android Lolipop 棒棒糖 5.0 系统。
  • 发自内心深处的好学特质。为了搞清楚 Android 触摸技术原理并能够根据项目需求得心应手进行实际应用,为了能够技术独立,不被牵制,随心所欲地创新(力所能及的范围内)。

尽管之前已经接触过一些简单的自定义 View 技术,但是为了更加有条理地进行下去,先后查阅了官方文档,google 了资料,学习借鉴了 SwipeMenuListView 的实现方式。
摸打滚爬了最终实现了 RecyclerView 侧滑菜单的雏形效果,但是还是存在已知的 bug,然后发生了一些外界因素,干扰了项目的正常运行,所以烂尾到现在的 2019 年。。。

之所以在 2019 年的最近重启了该项目,因为本人有个 2015 年写的个人 App 现在维护需要用到这个技术,也就是老生常谈烂大街的侧滑菜单交互,只不过这个是用在 App 首页那种侧滑显示菜单布局,当前已经实现的是 RecyclerView 里的 item 侧滑菜单,其实原理都是一样一样的,当时就考虑了这些,所以当时把 SwipeMenuRecyclerView 和自定义的侧滑布局 SwipeLayout 分离实现的。2013 年 App 侧滑交互已经开始流行了,类似 QQ 那种,后来又演变了各种侧滑效果的变种版本,包括后来的谷歌官方的 DrawerLayout。 还是一句话:原理都是一样一样的。现在的流行趋势是:

  • App 根本就是废弃了这种交互效果(我也不知道为什么,审美疲劳?感叹前端的风云变幻莫测!
  • 借鉴了 Google Android 原生系统桌面启动器的负一屏效果。现在的 QQ 设计的就是这个样子的(估计是借鉴的原生系统效果)

无独有偶,最近我把原先的自定义侧滑布局的各种 bug 解决了,完美地实现了负一屏侧滑布局效果,至少我人工测试了 N 遍。

为了乘热打铁,写了这边总结文章,下面开始进入严格的技术探讨篇(非技术人员可以略过)


技术

  1. #### 需求 程序是解决现实世界问题的抽象化模型和思维
    • App 在用户手指触摸屏幕时水平滑动(侧滑手势),打开或者关闭二级内容(负一屏或者称之为导航视图)
    • 实现 START(LEFT), END(RIGHT) , TOP, BOTTOM, ABOVE, BELOW 样式,多姿多彩,完美人生。
  2. #### 设计
    • 类名 站在抽象化思维角度上看,侧滑布局需要满足各种姿势的侧滑需求,并且能够应用在多种场景下(作为列表控件 itemview 的侧滑菜单,整屏侧滑),因此我们给这个自定义的布局类起名为 SwipeLayoutSwipeMenuLayout
    • 继承 首选 ViewGroup,而不是现有的布局容器(FrameLayout,LinearLayout。。。),因为这样可以更好地控制 SwipeLayout 下的 child view 的布局。
    • 依赖
      • GestureDetectorCompat 主要用它来监测 fling 手势。 Android SDK 和支持库中有大量提供手势方面的 public 接口,GestureDetectorCompat 类能够帮助你检测 Android 常见的标准手势,比如 单机(singleTap),双击(doubleTap),长按(longPress),滚动(scroll),滑翔(fling) 等等手势。当然了,可以完全不用GestureDetectorCompat 类,使用 VelocityTracker 来跟踪滚动速度然后根据需要判断触发 fling 手势。
      • OverScroller 用于计算 child view 的滚动偏移量。 官方已经废弃支持库中的 ScrollerCompatOverScroller 属于 SDK 中的类,顾名思义,OverScroller 拥有 over scroll(滑动超出正常的可滚动范围) 检测的能力,这样你就可以自己实现一些自定义 over scroll 的 ui 效果,比如类似 iOS 的粘性效果,或者 Android 系统默认的光晕效果。
  3. #### 开发
    • SwipeLayout 布局参数
      • app : layout_gravity 用于控制次视图(负一屏或菜单栏)的定位和布局。 这个 flag 的可选值有 START, END , TOP, BOTTOM, ABOVE, BELOW。 其中 START, END , TOP, BOTTOM 间互斥,ABOVE, BELOW 间互斥。 有效 12 种组合为:
        • 水平方向: STARTSTART | ABOVESTART | BELOWENDEND | ABOVEEND | BELOW
        • 垂直方向: TOPTOP | ABOVETOP | BELOWBOTTOMBOTTOM | ABOVEBOTTOM | BELOW
    • onMeasure 主要根据上级的 ViewGroup 传递过来 widthMeasureSpecheightMeasureSpec 测量 child view,通过 app : layout_gravity 找到 content view 和 secondary view。这里主要注意在 heightMeasureSpec 的 heightMode 不为 EXACTLY 的时候需要记录 那些 child view 的高度为 MATCH_PARENT 并设置一个MeasureSpec的高度为当前遍历完所有的child view后得出的最大的高度和 EXACTLY mode去重新测量这些 child view 以满足其布局要求。
    • onLayout

未完,待续。。。