每日一问:谈谈自定义 View 有些什么注意点

自定义 View 基本是每一名 Android 开发工程师都应该会的技能,其实搞清楚原理后,其实也没有那么困难,大多数童鞋都是直接被自定义 View 多还繁杂的流程所吓住。

对于自定义 View 和属性动画等操作,相信我无论如何也写不出扔物线的 https://hencoder.com/ 的高度,所以并不打算在这个上面浪费口舌。

不过,我们今天倒是可以来探讨一下,平时大家在自定义 View 的时候都有些什么需要我们去注意的。

对于自定义 View

对于大多数自定义 View 来说,如果是要绘制某些东西,直接在 onDraw() 方法中进行绘制即可,如果要处理触摸事件,那么直接重写 onTouchEvent() 并在里面编写自己的逻辑即可。大多数情况下,我们都需要重写 onMeasure(),如果不重写的话,就必须在外面指定好宽高,相信不会有人希望看到 wrap_contentmatch_parent 一样的展示效果吧。

对于 View 的测量的话,我想每一个人都得清楚 MeasureSpec 这个类的 Mode 和 size。对于 onMeasure() 里面的测量比较重要的可以移步到我之前的一篇文章:每日一问:谈谈你对 MeasureSpec 的理解。文章中详细介绍了 MeasureSpec 的测量模式和尺寸。不过文中并没有针对 UNSPECIFIED 这种「想多大就多大」的模式进行详细探究,对于 UNSPECIFIED 相关可以查看这篇文章:每日一问:详细说一下 MeasureSpec.UNSPECIFIED。

至此,我们基本可以总结到:直接继承自 View 的自定义 View 都是建议重写 onMeasure() 方法的,并且我们一定不应该忽略 MeasureSpec.UNSPECIFIED 这个测量模式。因为在可滚动的布局中摆放我们这个自定义 View 的时候,通常需要处理这种「想多大就多大」的情况。

除此之外,我们在自定义 View 的时候,还可以注意的点有:

  1. 如果有自定义属性,在构造方法中及时对 TypeArray 进行 recycler() 操作;
  2. onDraw()onTouchEvent() 方法中尽量避免创建对象或者进行耗时操作,如果过多出现会导致卡顿。
  3. invalidate()postInvalidate() 都用于刷新 View,区别是 invalidate() 可以在主线程调用,而 postInvalidate() 可直接使用在子线程。
  4. 比较重要级的资源要释放的时候可以重写 onDetachedFromWindow() 并进行释放。

对于自定义 ViewGroup

而对于自定义 ViewGroup,这里同样是只探讨直接继承自 ViewGroup 的自定义 ViewGroup。我们在编写的时候,必须重写 onLayout() 并在其中编写子 View 摆放的逻辑,同样我们也就必须重写 onMeasure() 去测量每一个子 View 的尺寸进而来确定自己的尺寸。

onMeasure() 中遍历子 View,并显式调用它们的 measure() 方法进而触发子 View 的 onMeasure() 方法得到每一个子 View 的尺寸。如果要处理触摸事件的话,需要重写 onInterceptTouchEvent() 或者 onTouchEvent() 方法。

那么,自定义 ViewGroup 还有哪些需要我们注意的呢?

对于 LayoutParams,我们在前面的 每日一问:关于 LayoutParams,你所应该知道的 一文中详细讲解了我们系统的 LayoutParams 的费心费力,讲到了为什么我们不设置甚至胡乱设置 LayoutParams 都不会导致崩溃的原因。所以我们在自定义 ViewGroup 的时候,最好也可以看看系统是怎么处理 LayoutParams 的。实际上,我们在自定义 ViewGroup 的时候最好重写下面四个方法。

  • generateDefaultLayoutParams()
    这个方法主要是在我们通过 addView 添加子 View 到里面的时候,没有添加 LayoutParams 的时候会回调进行处理。
  • generateLayoutParams(attrs: AttributeSet?)
    这个方法主要是用于我们在 inflate() View 的时候需要构造的一个 LayoutParams 处理。
  • checkLayoutParams(p: LayoutParams?)
    这个方法主要是判断我们代码中设置的 LayoutParams 是否正确,以防止我们在强转的时候发生异常。
  • generateLayoutParams(p: LayoutParams?)
    这个方法用于在我们外部设置错误的 LayoutParams 时纠正为正确的 LayoutParams

在自定义 ViewGroup 有触摸事件的时候,如果希望不影响子 View 的行为,需要重写 onInterceptTouchEvent() 方法去判断哪些行为是自己需要的,哪些是自己不需要的。

如果想要在 ViewGroup 中绘制一些东西,又没有在布局中设置 background 的时候,需要调用 setWillNotDraw(false) 进行处理。

可以还有许多,但这里由于时间关系就点到为止,总之,千万要注意 MeasureSpec.UNSPECIFIED,这个并没有诸多博客写到的很少见那么不重要。

你可能感兴趣的:(每日一问:谈谈自定义 View 有些什么注意点)