理解View
ViewRoot
viewRoot对应于ViewRootImpl类,它是连接WindowManager和DecorView的纽带,View的三大流程(measure、layout、draw是通过ViewRoot来完成的)。
DecorView是一个FrameLayout,view层的事件都是先经过DecorGView再传递给view。
measure、layout和draw的作用
-
measure用来测量view的宽和高。
-
layout用来确定view在父容器中放置的位置。
-
draw负责将view绘制在屏幕上。
view的绘制过程是从ViewRoot的performTraversals开始的。
Measure
类的measure过程由measure方法来完成,measure会调用view的onMeasure方法。在onMeasure方法中会调用getDefault方法对设置view的宽高的测量值。通常的是.AT_MOST和.EXCATLY两种情况,getDefault返回measureSpec的specSize(某些大小的参数)。还有一种情况为UNSPECIFIED,一般用于系统内部的测量过程,则设定的值为android:minWidth(无背景)或android:minWidth和背景宽度之间较大的一个(有背景)。
为什么直接继承View 的自定义控件需要重写onMeasure方法并设置warp_content时的自身大小
如果不重写,在布局中使用wrap_content就相当于使用match_parent。
LinearLayout的measure过程
在MeasureVertical中,系统会遍历子元素并对每个子元素执行MeasureChildBeforeLayout,这个方法会调用measure,这样就使得各个子元素依次进入measure过程。系统还会通过mTotalLength这个变量来储存LinearLayout在垂直方向的初步高度,决定这个变量的因素有子元素的高度和竖直方向上的margin。
获取我们设置的view的方法
首先获得Viewgroup
ViewGroup content = findViewById(R.android.id.content);
Viewgroup是view的集合。content.getChildAt(0)就是设置在setContentView的view。
自定义view
自定义view的分类
- 继承View重写onDraw
- 继承ViewGroup派生特殊的Layout
- 继承特定的View(比如TextView)
- 继承特定的ViewGroup(比如LinearLayout)
简单的自定义View示例
功能:在一块屏幕上显示一个圆。
由于功能比较简单,所以只需要在创建一个类后继承View再重写它的OnDraw()方法。
下图是运行效果
//处理后的ondrow代码(用于padding)
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int paddingLeft =getPaddingLeft();
int paddingRight =getPaddingRight();
int paddingTop =getPaddingTop();
int paddingBottom =getPaddingBottom();
int width =getWidth()-paddingLeft-paddingRight;
int heigth=getHeight()-paddingBottom-paddingTop;
int radius = Math.min(width,heigth)/2;
canvas.drawCircle(paddingLeft+width/2,paddingTop+heigth/2,radius,mPaint);
}
warp_content的设置在上面有写。
为自定义View添加自定义属性
- 在values目录下面创建自定义属性XML。比如attrs.xml(文件名并没有什么限制)。
- 在文件中定义属性。格式如下
在这里对name=CircleView的view声明了一个叫circle_color的属性。类型为color类型。 - 在View的构造方法中解析自定义属性的值并做相应的处理。
即用一个能保存所有属性值的变量类型TypeArray将所有的ciecleview所有的属性值读取出来。再用getcolor将对应的color类型的CircleView_circle_color(id为R.styleable.CircleView_circle_color)读取出来。最后一个参数为默认值。解析完后使用recycle实现资源回收。之后直接在layout中使用即可。 使用前要加schemas声明
xmlns:app=http://schemas.android.com/apk/res-auto
app是自定义属性的前缀