数据API 案例 开发者 关于
掌握聚合最新动态了解行业最新趋势
API接口,开发服务,免费咨询服务
新闻动态 > 媒体报道

安卓特殊形状控件的事件处理方案

不得不说,Android 对事件体系封装的非常棒,即便对事件体系不太了解的人,只要简单的调用方法就能使用,而且具有防呆设计,能够保证事件流的完整性和统一性,最大可能性的避免了事件处理的混乱,着实令人佩服。

然而世界上并没有绝对完美的东西,当【事件处理】遇上【自定义View】,一场好戏就开演了,玩的好叫坐镇军前,指挥千军万马而分毫不乱,玩的不好就是抓耳挠腮,眼见敌人前后包抄而无可奈何。

特殊形状控件

在通常的情况下,自定义 View 直接使用系统的事件体系处理就行,我们也不需要特殊处理,然而当一些特殊的控件出现的时候,麻烦就来了,举个栗子:

这是一个在遥控器上非常常见的按键布局,注意中间上下左右选择的部分,看起来十分简单,然而当你真正准备在手机上实现的时候麻烦就出现了。因为所有的View默认都是矩形的,所以事件接收区域也是矩形的,如果直接使用系统提供的 View 来组合出一摸一样的布局也很简单,但点击区域该如何处理?显然这样有部分点击区域是在控件外面的,并且控件之间会产生重叠区域,点击的时候容易判断错误,例如:

红色方框表示用 View 组合的情况下,单个 View 的可点击区域。

当我们面对这样比较奇特的控件的时候,有很多处理办法,比较投机的一种就是背景贴一个静态图,按钮做成透明的,设置小一点,放在对应的位置,这样可以保证不会误触,当然了如果想要点击效果可以在按钮按下的时候更新一下背景图,这样虽然也可以,但可点击区域会变小,体验效果会变差。设计方案变得非常复杂,而且逻辑也不容易处理,可以说是一种非常糟糕的设计。

当然了,看了我这么多文章的小伙伴应该也猜到我接下来要说什么了,没错,就是自定义 View。当我们面对一些奇葩控件的时候,自定义 View 就变成了一种非常好用的处理方案。

相信小伙伴们看过 前面的文章 之后,对各种图形的绘制已经不成问题了,所以我们直接处理重点问题。

特殊形状控的点击区域判断

要进行特殊形状的点击判断,要用到一个之前没有使用过的类:Region。

Region 直接翻译的意思是 地域,区域。在此处应该是区域的意思。它和 Path 有些类似,但 Path 可以是不封闭图形,而 Region 总是封闭的。可以通过 setPath 方法将 Path 转换为 Region。

本文中我们重点要使用到的是 Region 中的 contains 方法,这个方法可以判断一个点是否包含在该区域内。

下面是一个简单的示例程序:

安卓特殊形状控件的事件处理方案   DiyCode1.png

代码中比较重要的内容都用 ▼ 符号标记出来了。

上述代码非常简单,就是创建了两个 Path,在 Path 中添加圆形,之后将 Path 设置到 Region 中,当手指在屏幕上按下的时候判断手指按下位置是否在 Region 区域内。

代码整体逻辑非常简单,大家测试一下就行了。

画布变换后坐标转换问题

还是上述的例子,绘制一个上下左右选择按键,这个控件是上下左右对称的,熟悉我代码风格的小伙伴都知道,如果遇上这种问题,我肯定是要将坐标系平移到这个控件中心的,这样数据比较好计算,然而进行画布变换操作会产生一个新问题:手指触摸的坐标系和画布坐标系不统一,就可能引起手指触摸位置和绘制位置不统一。

举个栗子:

在手指按下位置绘制一个圆。

安卓特殊形状控件的事件处理方案   DiyCode2.png

可以看到,直接拿手指触摸位置的坐标来绘制会导致绘制位置不正确,大概会像这样子:

两者坐标是相同的,但是由于坐标系不同,导致实际显示位置不同。

那么问题来了,我们在之前的文章中讲过,映射不同坐标系的坐标用 什么来着?

是 Matrix。

如果看过我之前的文章但没有想起来的说明你们根本没有认真看,全部拖出去糟蹋 5 分钟!

没看过的点 Matrix原理 和 Matrix详解 。

Matrix 是一个矩阵,主要功能是坐标映射,数值转换。

那么接下来我们就对上面的示例进行简单的改造一下,让触摸位置和实际绘制绘制重合。

注意:比较重要的修改位置用▼标记出来了。

安卓特殊形状控件的事件处理方案   DiyCode3.png

绘制结果:

小白点和黑色的圆没有完全重合是因为系统显示触摸位置的绘制逻辑和我使用的绘制逻辑不太相同,两者的位置是一样的。

其实核心部分就这两点:

安卓特殊形状控件的事件处理方案   DiyCode4.png

  1. 使用全局坐标系
  2. 使用逆矩阵的 mapPoints

原理嘛,其实非常简单,我们在画布上正常的绘制,需要将画布坐标系转换为全局坐标系后才能真正的绘制内容。所以我们反着来,将获得到的全局坐标系坐标使用当前画布的逆矩阵转化一下,就转化为当前画布的坐标系坐标了,如果对 Matrix原理 和Matrix详解 理解了,即便我不说你们也肯定会想到这个方案的。

仿遥控器按钮代码示例

在解决了上述两大难题之后,相信不论形状如何奇葩的自定义控件,基本上都难不倒大家了,最后用一个简单的示例作为结尾,还是文章开头所举的例子,核心内容就是上面讲的两个东西。

安卓特殊形状控件的事件处理方案   DiyCode5.png

运行效果:

当手指在某一区域活动时,该区域会高亮显示,如果注册了监听器,点击某一区域会触发监听器回调。

总结

本文虽然代码比较多,但核心概念非常简单,主要涉及以下两点:

  1. Region 的区域检测。
  2. Matrix 的坐标映射。

这两个知识点都不是很难,然而灵活运用起来却是非常强大的,如果有对 Matrix 不了解的小伙伴,推荐去看我 之前的文章,里面有关于Matrix的详细介绍,


由于字符限制本文代码以图片形式呈现,需要了解详情请点击原文

原文来自: GcsSloop的博客

掌握聚合最新动态了解行业最新趋势
API接口,开发服务,免费咨询服务
新闻动态 > 媒体报道
安卓特殊形状控件的事件处理方案
发布:2016-11-16

不得不说,Android 对事件体系封装的非常棒,即便对事件体系不太了解的人,只要简单的调用方法就能使用,而且具有防呆设计,能够保证事件流的完整性和统一性,最大可能性的避免了事件处理的混乱,着实令人佩服。

然而世界上并没有绝对完美的东西,当【事件处理】遇上【自定义View】,一场好戏就开演了,玩的好叫坐镇军前,指挥千军万马而分毫不乱,玩的不好就是抓耳挠腮,眼见敌人前后包抄而无可奈何。

特殊形状控件

在通常的情况下,自定义 View 直接使用系统的事件体系处理就行,我们也不需要特殊处理,然而当一些特殊的控件出现的时候,麻烦就来了,举个栗子:

这是一个在遥控器上非常常见的按键布局,注意中间上下左右选择的部分,看起来十分简单,然而当你真正准备在手机上实现的时候麻烦就出现了。因为所有的View默认都是矩形的,所以事件接收区域也是矩形的,如果直接使用系统提供的 View 来组合出一摸一样的布局也很简单,但点击区域该如何处理?显然这样有部分点击区域是在控件外面的,并且控件之间会产生重叠区域,点击的时候容易判断错误,例如:

红色方框表示用 View 组合的情况下,单个 View 的可点击区域。

当我们面对这样比较奇特的控件的时候,有很多处理办法,比较投机的一种就是背景贴一个静态图,按钮做成透明的,设置小一点,放在对应的位置,这样可以保证不会误触,当然了如果想要点击效果可以在按钮按下的时候更新一下背景图,这样虽然也可以,但可点击区域会变小,体验效果会变差。设计方案变得非常复杂,而且逻辑也不容易处理,可以说是一种非常糟糕的设计。

当然了,看了我这么多文章的小伙伴应该也猜到我接下来要说什么了,没错,就是自定义 View。当我们面对一些奇葩控件的时候,自定义 View 就变成了一种非常好用的处理方案。

相信小伙伴们看过 前面的文章 之后,对各种图形的绘制已经不成问题了,所以我们直接处理重点问题。

特殊形状控的点击区域判断

要进行特殊形状的点击判断,要用到一个之前没有使用过的类:Region。

Region 直接翻译的意思是 地域,区域。在此处应该是区域的意思。它和 Path 有些类似,但 Path 可以是不封闭图形,而 Region 总是封闭的。可以通过 setPath 方法将 Path 转换为 Region。

本文中我们重点要使用到的是 Region 中的 contains 方法,这个方法可以判断一个点是否包含在该区域内。

下面是一个简单的示例程序:

安卓特殊形状控件的事件处理方案   DiyCode1.png

代码中比较重要的内容都用 ▼ 符号标记出来了。

上述代码非常简单,就是创建了两个 Path,在 Path 中添加圆形,之后将 Path 设置到 Region 中,当手指在屏幕上按下的时候判断手指按下位置是否在 Region 区域内。

代码整体逻辑非常简单,大家测试一下就行了。

画布变换后坐标转换问题

还是上述的例子,绘制一个上下左右选择按键,这个控件是上下左右对称的,熟悉我代码风格的小伙伴都知道,如果遇上这种问题,我肯定是要将坐标系平移到这个控件中心的,这样数据比较好计算,然而进行画布变换操作会产生一个新问题:手指触摸的坐标系和画布坐标系不统一,就可能引起手指触摸位置和绘制位置不统一。

举个栗子:

在手指按下位置绘制一个圆。

安卓特殊形状控件的事件处理方案   DiyCode2.png

可以看到,直接拿手指触摸位置的坐标来绘制会导致绘制位置不正确,大概会像这样子:

两者坐标是相同的,但是由于坐标系不同,导致实际显示位置不同。

那么问题来了,我们在之前的文章中讲过,映射不同坐标系的坐标用 什么来着?

是 Matrix。

如果看过我之前的文章但没有想起来的说明你们根本没有认真看,全部拖出去糟蹋 5 分钟!

没看过的点 Matrix原理 和 Matrix详解 。

Matrix 是一个矩阵,主要功能是坐标映射,数值转换。

那么接下来我们就对上面的示例进行简单的改造一下,让触摸位置和实际绘制绘制重合。

注意:比较重要的修改位置用▼标记出来了。

安卓特殊形状控件的事件处理方案   DiyCode3.png

绘制结果:

小白点和黑色的圆没有完全重合是因为系统显示触摸位置的绘制逻辑和我使用的绘制逻辑不太相同,两者的位置是一样的。

其实核心部分就这两点:

安卓特殊形状控件的事件处理方案   DiyCode4.png

  1. 使用全局坐标系
  2. 使用逆矩阵的 mapPoints

原理嘛,其实非常简单,我们在画布上正常的绘制,需要将画布坐标系转换为全局坐标系后才能真正的绘制内容。所以我们反着来,将获得到的全局坐标系坐标使用当前画布的逆矩阵转化一下,就转化为当前画布的坐标系坐标了,如果对 Matrix原理 和Matrix详解 理解了,即便我不说你们也肯定会想到这个方案的。

仿遥控器按钮代码示例

在解决了上述两大难题之后,相信不论形状如何奇葩的自定义控件,基本上都难不倒大家了,最后用一个简单的示例作为结尾,还是文章开头所举的例子,核心内容就是上面讲的两个东西。

安卓特殊形状控件的事件处理方案   DiyCode5.png

运行效果:

当手指在某一区域活动时,该区域会高亮显示,如果注册了监听器,点击某一区域会触发监听器回调。

总结

本文虽然代码比较多,但核心概念非常简单,主要涉及以下两点:

  1. Region 的区域检测。
  2. Matrix 的坐标映射。

这两个知识点都不是很难,然而灵活运用起来却是非常强大的,如果有对 Matrix 不了解的小伙伴,推荐去看我 之前的文章,里面有关于Matrix的详细介绍,


由于字符限制本文代码以图片形式呈现,需要了解详情请点击原文

原文来自: GcsSloop的博客

电话 0512-88869195
数 据 驱 动 未 来
Data Drives The Future