Android View中onSave(),onRestore(),getWidth(),getMeasureWidth()方法解析

前言:

今天花了点时间来研究View中的onSave(),onRestore(),getWidth(),getMeasureWidth()方法的作用与原理,在csdn上看到一篇写得很详细的文章。各位可以稳步去看看。
地址:http://blog.csdn.net/harvic880925/article/details/39080931
下面我文章姑且是记录下自己对这些方法的理解

一、onLayout()与onMeasure()

1)、onMeasure()

这个是用来测量view及其内容所占宽高来确定view的宽高的方法。
在父类中onMeasure(int measureWidthSpec,int measureHeightSpec)方法的实现如下:

public static int getDefaultSize(int size, int measureSpec) {
int result = size;//而这个size是根据background来的,如果没有
//设置background,则size=0,否则,就是background的宽度
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);

    switch (specMode) {
    case MeasureSpec.UNSPECIFIED:
        result = size;
        break;
    case MeasureSpec.AT_MOST:
    case MeasureSpec.EXACTLY:
        result = specSize;
        break;
    }
    return result;
}


所以当子类继承View时,重写onMeasure(int measureWidthSpec,int measureHeightSpec)方法时,可以在对测量模式进行解码时,给定默认值,如下;

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int measureWidth = measreSpec(widthMeasureSpec);
int measureHeight = measreSpec(heightMeasureSpec);
setMeasuredDimension(measureWidth,measureHeight);
}
private int measreSpec(int widthMeasureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(widthMeasureSpec);
int specSize = MeasureSpec.getSize(widthMeasureSpec);
if(specMode == MeasureSpec.UNSPECIFIED){
//这里是关键,当view没有指定大小时,给默认值
result = 400;
}else {
result = specSize;
}

    return result;
}

2),onLayout():

当onMeasure测量到View及其内容的大小后,就要调用onLayout()方法,当调用onLayout()方法后,View及其子View中的layout就会被调用,用以确定各自在viewGroup中的位置。
记住:如果重写的onLayout()方法,那么在onLayout()方法里面一定要遍历View所有的子View,然后调用layout()方法。
如下:

/**
* 覆写onLayout,其目的是为了指定视图的显示位置,方法执行的前后顺序是在onMeasure之后,因为视图肯定是只有知道大小的情况下,
* 才能确定怎么摆放
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// 记录总高度
int mTotalHeight = 0;
// 遍历所有子视图
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View childView = getChildAt(i);

        // 获取在onMeasure中计算的视图尺寸  
        int measureHeight = childView.getMeasuredHeight();  
        int measuredWidth = childView.getMeasuredWidth();  


childView.layout(l, mTotalHeight, measuredWidth, mTotalHeight
+ measureHeight);

        mTotalHeight += measureHeight;  

    }  
}  

二、getWidth()和getMeasureWidth()

1),getWidth():

获取View的宽度,不是原始宽度,是View在父布局中被layout好后的宽度,即我们能看到的宽度(单位:px)。
getHeight()跟它是一个意思。

2),getMeasureWidth():

获取View的原始宽度。何谓原始,就是没有经过任何的裁剪操作的原始数据(单位:px)。
如一块准备做衣服的布,在被裁剪之前的宽度。因此理论上来说getMeasureWidth()>=getWidth();
注意:要始getMeasureWidth()获取到原始数据,在它被调用之前要调用measure(0,0)方法进行触发,
否则获取到的值与getWidth是一样的。
下面是在onDraw写的测试代码及返回的结果:

@Override
protected void onDraw(Canvas canvas) {
measure(0,0);
canvas.drawColor(Color.DKGRAY);
canvas.save();
int measureWidth = getMeasuredWidth();
int measureHeight = getMeasuredHeight();
int viewWidth = getWidth();
int viewHeight = getHeight();

    LogUtils.e("measureWidth:"+measureWidth+
    "\nmeasureHeight:"+measureHeight+
    "\nviewWidth:"+viewWidth+
    "\nviewHeight:"+viewHeight);

E/c-life: measureWidth:400//这是我在onMeasure()方法中给的默认值为400
measureHeight:400
viewWidth:800//这是因为我在xml中父布局中指定宽度为400dp,因为结果为px,所以为800px
viewHeight:1138

getHeight()与getMeasureHeight()原理是一样的。

三、onSave()和restore()

相信有好多的同学,跟我一样,之前我一直以为onSave()只是简单的保存,怕已经绘好的东西丢失,
而restore()则从来没用,下面就记录下今天写demo得出的结论:

1),onSave()

android 官方源码的注释说明大概就是:保存当前画布的状态至私有栈中,对接下来的
对画布进行平移,缩放,旋转,倾斜等操作并不影响。
注意:里面说到了是保存到栈中,既然是栈,所以就有先进后出,后进先出。
那onSave()方法这保存的状态到底是什么了?
借用harvic880925他的博客,onSave可以理解为保存的是当前画布的图层,因为它在下一次draw时,又是一个新的图层,而它保存的是当前图层的起始位置,背景色,图层里面已经画好的图等一系列东东。
那把这些东西保存到栈里面有什么用?

2),restore()

同样,官方文档:恢复到上次保存的状态。restore()调用次数不能超过onSave()次数。
看懂上面onSave()是保存到栈里面的,这里就很容易明白,因为restore()恢复,就是从栈里面push,
每次restore(),都把栈顶的状态push出来,所以如果restore()次数大于onSave()次数,就会报数组越界Error.

作者harvic880925对此已经写了一个很好的demo,各位可以直接移步去进行赏析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值