|
1 | | -# 特殊控件的事件处理方案 |
2 | | - |
| 1 | +# 特殊形状控件的事件处理方案 |
3 | 2 |
|
4 | 3 | 本文带大家了解 Android 特殊形状控件的事件处理方式,主要是利用了 Region 和 Matrix 的一些方法,超级实用的事件处理方案,相信看完本篇之后,任何奇葩控件的事件处理都会变得十分简单。 |
5 | 4 |
|
|
11 | 10 | > |
12 | 11 | > 本文中所有的 自定义View 均继承自 CustomView ,这是一个自定义的超类,目的是简化 自定义View 部分常用操作,你可以在 [ViewSupport](https://github.com/GcsSloop/ViewSupport/wiki/CustomView) 中找到它以及关于它的简介。 |
13 | 12 |
|
| 13 | +## ⚠️ 警告:测试本文章示例之前请关闭硬件加速。 |
| 14 | + |
14 | 15 | ## 特殊形状控件 |
15 | 16 |
|
16 | 17 | 在通常的情况下,自定义 View 直接使用系统的事件体系处理就行,我们也不需要特殊处理,然而当一些特殊的控件出现的时候,麻烦就来了,举个栗子: |
@@ -86,8 +87,10 @@ public class RegionClickView extends CustomView { |
86 | 87 |
|
87 | 88 | @Override |
88 | 89 | protected void onDraw(Canvas canvas) { |
| 90 | + // ▼注意此处将全局变量转化为局部变量,方便 GC 回收 canvas |
| 91 | + Path circle = circlePath; |
89 | 92 | // 绘制圆 |
90 | | - canvas.drawPath(circle1,mDeafultPaint); |
| 93 | + canvas.drawPath(circle,mDeafultPaint); |
91 | 94 | } |
92 | 95 | } |
93 | 96 | ``` |
@@ -522,6 +525,35 @@ public class RemoteControlMenu extends CustomView { |
522 | 525 |
|
523 | 526 |
|
524 | 527 |
|
| 528 | +## 关于硬件加速的问题 |
| 529 | + |
| 530 | +**硬件加速是个好东西,但是处理不好会引起诸多问题,博主为了怕麻烦我一直关闭硬件加速。** |
| 531 | + |
| 532 | +然而硬件加速在 Android 4.0 以上是默认开启的,这就导致了有好几位魔法师反馈测试结果和我的测试结果不同,我来简单说明一下硬件加速干了什么事情,以及这些文章中的锅是如何产生的,应该由谁来背。 |
| 533 | + |
| 534 | +我在 [Matrix 原理][Matrix_Basic] 中说过 Matrix 的作用: **Matrix作用就是坐标映射。** |
| 535 | +其核心功能就是将单个 View 的坐标系转化为屏幕(物理)坐标系,虽然转换一次费不了多少时间,但是当执行动画效果等需要大量快速重绘的情况下,耗费的时间就需要考量一下了,于是乎,硬件加速干了一件非常**精明**的事情,**把所有画布坐标系都设置为屏幕(物理)坐标系**,之后在 View 绘制区域设置一个遮罩,保证绘制内容不会超过 View 自身的大小,**这样就直接跳过坐标转换过程,可以节省坐标系之间数值转换耗费的时间**。因此导致了以下问题: |
| 536 | + |
| 537 | +1. 开启硬件加速情况下 event.getX() 和 不开启情况下 event.getRawX() 等价,获取到的是屏幕(物理)坐标 (本文的锅)。 |
| 538 | +2. 开启硬件加速情况下 event.getRawX() 数值是一个错误数值,因为本身就是全局的坐标又叠加了一次 View 的偏移量,所以肯定是不正确的 (本文的锅)。 |
| 539 | +3. 从 Canvas 获取到的 Matrix 是全局的,默认情况下 x,y 偏移量始终为0,因此你不能从这里拿到当前 View 的偏移量 ( Matrix系列文章中的锅 )。 |
| 540 | +4. 由于其使用的是遮罩来控制绘制区域,所以如果重绘 path 时,如果 path 区域变大,但没有执行单步操作会导致 path 绘制不完整或者看起来比较奇怪 (Path系列文章中的锅)。 |
| 541 | + |
| 542 | +很显然,这个硬件加速有点6,制造了各种锅想让我来背,然而智慧的我早已看穿一切,默默的把硬件加速关闭了,因为我不知道它还有多少锅没亮出来。 |
| 543 | + |
| 544 | +**这里顺便挖个坑,等我搞明白硬件加速扔锅的逻辑之后,专门写一篇硬件加速的文章,把硬件加速的锅全埋进去,再也不背这口大黑锅了**。 |
| 545 | +**(╯°Д°)╯︵ ┻━┻** |
| 546 | + |
| 547 | + |
| 548 | + |
| 549 | +**个人建议:** |
| 550 | + |
| 551 | +1. 如果应用不需要大量重绘,那么硬件加速开启和关闭都无所谓,推荐关闭。 |
| 552 | +2. 如果应用要兼容到 3.0 以下,建议不要使用硬件加速的特性,或者进行兼容性处理。 |
| 553 | +3. 如果应用存在大量的动画等需要快速重绘的场景,在开启硬件加速时注意测试。 |
| 554 | +4. 如果 自定义View 出现与绘图相关的异常,请务必检查一下硬件加速。 |
| 555 | +5. 如果想关掉硬件加速看这里: [Android如何关闭硬件加速](https://github.com/GcsSloop/AndroidNote/issues/7) 。 |
| 556 | + |
525 | 557 | ## 总结 |
526 | 558 |
|
527 | 559 | 本文虽然代码比较多,但核心概念非常简单,主要涉及以下两点: |
|
0 commit comments