从源码来理解自定义View
以下这些内容都是理解自定义View的基础知识点。
首先需要理解ViewGroup的概念,ViewGroup是一个特殊的View,它可以包含其它多个View,这些被包含的View也被称为childView(子View)。
一个ViewGroup可以包含多个子View,同时,这个子View也可以是ViewGroup。
例如,LinearLayout是一个ViewGroup,在里面添加一个Button,则这个Button是LinearLayout的子View。
那么,一个View是如何呈现在手机屏幕上的呢?
View的三大工作流程:
1.[测量流程] onMeasure(int widthMeasureSpec, int heightMeasureSpec)
在谷歌给的源码中,它是这么解释的:Ask all children to measure themselves and compute the measurement of this layout based on the children. 意思是:要求所有的子View测量自己,然后通过这些测量值,计算这个承载所有子View的layout。
这个方法的作用就是用于测量View的尺寸。
2.[布局流程] onLayout(boolean changed, int l, int t, int r, int b)
在谷歌给的源码中,它是这么解释的:Position all children within this layout. 意思是:确定所有子View的位置。
作用即是确定所有View的位置。
3.[绘制流程] onDraw(Canvas canvas)
- 作用就是将View绘制到屏幕上
1. onMeasure() 需要明白的方法
① public boolean shouldDelayChlidPressedState() {return false;}
任何一个不需要使用滑动的布局都要使用它,不滚动的子类,一般应该重写此方法并返回false。
② getChildCount()
返回ViewGroup里所有子View的个数
③ getChlidAt(int)
返回一个在ViewGroup里指定位置的View
④ getVisibility()
返回视图的可见性状态,有:VISIBLE/INVISIBLE/GONE
⑤ meassureChildWithMargins(View childView, int parentWidthMeasureSpec,int widthUsed, int parentHeighMeasureSpec, int heightUsed)
要求子View测量好自己,要求考虑到父容器的宽高,及额外的空间
⑥ LayoutParams
布局参数类
⑦ childView.getLayoutParams()
获取子View的布局参数
⑧ childView.getMeasuredWidth()
以Raw的方式计算获取宽度(自行百度getX和getRawX的区别)
⑨ childView.getMeasuredWidthAndState()
跟上面一样,但不是以Raw方式
⑩ getSuggestedMinimumHeight()
返回这个View建议使用的最小高度
⑩① resolveSizeAndState()
用于创建最终的宽度或高度值,这个助手返回适当的视图所需的尺寸
⑩② 这个方法本身:
onMeasure(int widthMeasureSpec, int heightMeasureSpec)中的两个形参,即为ViewGroup最初的测量值。
⑩③ setMeasuredDimension(int measuredWidth, int measuredHeight)
注意:这个方法在最后一定要调用,否则会在测量期间引发一个异常。它用来存储最后测量得到的宽和高。
2. onLayout() 需要明白的方法
① child.layout(left, top, right, bottom)
摆放这个子View
② 这个方法本身:
onLayout(boolean changed, int l, int t, int r, int b) 当这个视图应该给每个子View分配一个大小和位置时调用。changed:当View发生改变时,changed=true
3. onDraw() 需要理解的知识点
- 1.在onDraw方法前创建对象是一个非常重要的优化,View重新绘制的频率非常高,很多绘图的对象需要昂贵的初始化。Android官方建议的屏幕刷新率为60FPS,那么计算下来,每一次调用onDraw方法,可以执行的时间长度仅仅为16ms。在onDraw方法中创建图形对象显著降低性能,会让用户界面变得迟缓。
- 2.为了正确地画出你自定义的视图,精确的测量很重要,不应该对屏幕上的视图大小做出假设,而是应该通过onMeasure()来进行测量。
- 3.如果你认为不需要对其尺寸进行特殊控制,只需要重写一个方法: onsizeChanged()
- 4.onDraw()常用到的方法:
- 绘制文本:使用drawText(),调用setTypeface()指定字体,文本颜色调用setColor()
- 绘制shape:使用drawRect()/drawOval()/drawArc(),指定它们为轮廓或者填充,调用setStyle()
- 绘制更复杂的shape:使用Path类,通过Path对象添加线条或曲线路径,然后drawpath()绘制形状,形状可以为轮廓或充满,调用setStyle()
- 渐变:定义渐变填充,使用LinearGradient对象,吊桶setShader()来使用这个渐变填充的shape
- Bitmap:这个直接调用drawBitmap()
看完上述内容后,再来从代码案例中理解上述的知识点:
hongyang大神的博客,Android 手把手教您自定义ViewGroup(一)
一切清晰明了