对于接触安卓开不到一年的自己来说,总结下view的生命周期还是有非常重要的好处的,不仅表达了对view的理解,也可以给初学者学习参考;本文就粗略总结下view的加载机制,上一文中给大家粗略介绍了下安卓的绘图基础和原理,也偶尔提到了安卓的view是通过解析xml,然后变成Java对象,再通过父类的canvas和paint绘制出来的,如果往上层理解,简单的概括下,就是在activty里通过这是ContenView方法,安卓WindownManger采用pul器l解析对应控件然后经过测量,摆放,最后绘制到界面上的,看了安卓关于view的源代码,也不难解释为何有的朋友在开发中获取键盘高度或者某一控件高度获取为零的原因,因为view在渲染时候并未测绘出来,而此时的实际高度必定为零。
主要:接收XML完成,进行测量,摆放,绘制,绑定到activty中 其自生还有很多API在不同场景触发。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
// TODO Auto-generated method stub
super.onLayout(changed, left, top, right, bottom);
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
}
@Override
protected void onFinishInflate() {
// TODO Auto-generated method stub
super.onFinishInflate();
}
@Override
protected void onAttachedToWindow() {
// TODO Auto-generated method stub
super.onAttachedToWindow();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
int width = 400;
int height = 800;
measure(width, height);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
int width = widthMeasureSpec;
int height = 0;
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
//获取子view的测量高度
height = child.getMeasuredHeight();
//获取子view的测量宽度
width = child.getMeasuredWidth();
//进行赋值测量值
getChildAt(i).measure(width, height);
height += height;
}
setMeasuredDimension(width, height);//当然我们可以直接设置宽高,无需调用父类onMessur的方法
//super.onMeasure(width, height);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int left = 0;
int top = 0;
int right = 60;
int bottom = 70;
layout(l, t, r, b);
}
"margin-top:0px; margin-bottom:1.1em; outline:none!important">"font-size:14px"> 安卓中用来做我们测好已经摆放好view的绘制工作,上篇文章中讲到,此方法结Canvas和Paint进行基础绘制工作,如果自定义控件 这些绘制需要我们自己去绘制 父类的onDraw()为抽象类,具体绘制情况基于你继承的父类控件类型(IamgeView,TextView等),而ViewGroup是有VIew特性的他是循环子类的onDraw()方法。这就解释了我们如果不继承任何类型的view,如果不重写Ondraw方法,即使已经做了测绘和布局摆放,也无法显示出来,因为系统无法识别你的view该调那个对应的ondraw()方法,其父类绘制源码也未做任何处理。
"code" class="java">@Override
如果在Viewgroup中,和上面的测量方法一样,依然采用遍历子控件,依次进行Layout(),到最后还依然递归到onLayout上来,因为不难理解,这里不再解释,值得强调的是,如果你在ViewGroup中重写 onLayout(),不能在继续super.onLayout()方法。因为ViewGruop已经没有可以存放的父类了。4 onDraw() 充当我们的房子的的切墙和粉刷工作。安卓中用来做我们测好已经摆放好view的绘制工作,上篇文章中讲到,此方法结Canvas和Paint进行基础绘制工作,如果自定义控件 这些绘制需要我们自己去绘制 父类的onDraw()为抽象类,具体绘制情况基于你继承的父类控件类型(IamgeView,TextView等),而ViewGroup是有VIew特性的他是循环子类的onDraw()方法。这就解释了我们如果不继承任何类型的view,如果不重写Ondraw方法,即使已经做了测绘和布局摆放,也无法显示出来,因为系统无法识别你的view该调那个对应的ondraw()方法,其父类绘制源码也未做任何处理。
@Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub Paint paint = new Paint(); canvas.drawLine(startX, startY, stopX, stopY, paint); super.onDraw(canvas); }
当以上所有工作完成之后,触发此方法,用于绑定到setContView()的Activity上,此时生命周期交由Activity使用,但不代表view停止工作。onDetachedFromWindow()和此方法相反,当view被移除出去之后触发。
@Override
public void clearFocus() {
// TODO Auto-generated method stub
super.clearFocus();
}
@Override
public void invalidate(int l, int t, int r, int b) {
// TODO Auto-generated method stub
super.invalidate(l, t, r, b);
}
@Override
public void requestLayout() {
// TODO Auto-generated method stub
super.requestLayout();
}
@Override
public void forceLayout() {
// TODO Auto-generated method stub
super.forceLayout();
}
@Override
protected Parcelable onSaveInstanceState() {
// TODO Auto-generated method stub
return super.onSaveInstanceState();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
// TODO Auto-generated method stub
super.onSizeChanged(w, h, oldw, oldh);
}
@Override
protected void onAnimationStart() {
// TODO Auto-generated method stub
super.onAnimationStart();
}
@Override
protected void onConfigurationChanged(Configuration newConfig) {
// TODO Auto-generated method stub
super.onConfigurationChanged(newConfig);
}
2 requestLayout()
请求重新摆放,给予位置。
3 forceLayout()
清除已摆放的位置数据,释放view的具体坐标。
4 onSizeChanged()
在view尺寸发生变化是触发。一般父布局的大小不会发生变化的,手机屏幕固定
5 onConfigurationChanged()
横竖屏切换之后触发,此时view将从测绘,摆放和绘制重新走一遍。
6 onAnimationStart()
view有设置动画是触发,默认无动画,此方法对当前view截取bitmap镜像,不断调用draw进行绘制,
7 onSaveInstanceState()
保存当前的属性状态,便于切换view之前进行可序列传输,当我view不可见的时候,此时view的大小,位置和绘制的镜像位图,并未从内存中清除,当view再次显示的时候触发此方法。
到此大致规程已经熟知,
当view执行onMeasure()是遍历到存在子类的时候就会调用子子类Measure()的方法,子类在继续调用其onMeasure()方法,当其子类无子类的时候跳出交由父类继续执行onMeasure()方法,依次递归,直到所有子类全部测量完毕为止进行onMeasure()后继续onLayout,其如上图一样,继续遍历子view,如果有子类存在调用其Layout,子类内部调用onLayout(),依次递归。直到所有控件全部布局完毕,后开启ondraw()。
如下图:
当viewGroup里存在两个子类,一个view3和ViewGroup2,这是就会调用其两个子类的XXX方法,子类的XXX内部又会调用其子类的onXXx()。ViewGroup检测到View存在的时候又会调用其View1,.XXX(),依次递归。
ps:当然子控件的坐标不是按屏幕左上角原点位置计算,而是按父亲控件的左上角起点计算, 而事件中的触摸坐标不管是哪个view都是按屏幕原点计算的.
通过以上步骤,我们可以总结出,view的加载过程其实就是一个不断遍历其子节点再一次添加的过程,和其xml的解析如出一辙。欢迎大家阅读。