关闭

自定义View中的onMeasure,measureChild与measureChildren

标签: androidonMeasuremeasureChild自定义View
375人阅读 评论(0) 收藏 举报
分类:

在重写的onMeasure的时候我们会调用super.onMeasure(widthMeasureSpec, heightMeasureSpec);

来一起看下源码:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
    }
原来就是默认的为我们调用了setMeasuredDimension(设置控件需要绘制的大小),英文是Measure测量其实就可以理解为计算并设置出该控件需要的大小。

继续来看setMeasuredDimension方法

protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
        boolean optical = isLayoutModeOptical(this);
        if (optical != isLayoutModeOptical(mParent)) {
            Insets insets = getOpticalInsets();
            int opticalWidth  = insets.left + insets.right;
            int opticalHeight = insets.top  + insets.bottom;

            measuredWidth  += optical ? opticalWidth  : -opticalWidth;
            measuredHeight += optical ? opticalHeight : -opticalHeight;
        }
        mMeasuredWidth = measuredWidth;
        mMeasuredHeight = measuredHeight;

        mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;
    }
isLayoutModeOptical返回的boolean类型,返回的是是否超出了我们的视觉边界,大家使用的时候都知道我们要传入的widthMeasureSpec, heightMeasureSpec是父控件的宽和高,这里就解释了为什么我们需要传入这两个值了,就是为了控制不超出父控件的大小


现在来看看measureChild和measureChildren:

measureChild是用来测量子View的宽高(我更倾向于理解为设置子View的宽高)。

measureChild(View child, int parentWidthMeasureSpec,int parentHeightMeasureSpec);

见源码

protected void measureChild(View child, int parentWidthMeasureSpec,
            int parentHeightMeasureSpec) {
        final LayoutParams lp = child.getLayoutParams();

        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
                mPaddingLeft + mPaddingRight, lp.width);
        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
                mPaddingTop + mPaddingBottom, lp.height);
        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    }

getChildMeasureSpec有三个参数,第一个是需要的大小(这里传的父控件的长宽,与上面的OnMeasure原理类似),第二个是当前子View的padding大小,第三个是此子View当前想要的设置的大小。

child.measure就是计算并设置出该child需要的大小。


所以每次我们在自定义View中得到测量(按英文就是测量...)子View的宽和高之后可以直接得到子View的宽高。


<span style="white-space:pre">			</span>View child = getChildAt(i);
			// 测量子View的宽和高
			measureChild(child, widthMeasureSpec, heightMeasureSpec);
			// 得到LayoutParams
			MarginLayoutParams lp = (MarginLayoutParams) child
					.getLayoutParams();

			// 子View占据的宽度
			int childWidth = child.getMeasuredWidth() + lp.leftMargin
					+ lp.rightMargin;
			// 子View占据的高度
			int childHeight = child.getMeasuredHeight() + lp.topMargin
					+ lp.bottomMargin;


measureChildren是用来测量所有子View的宽高。

理解起来很简单:

protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
        final int size = mChildrenCount;
        final View[] children = mChildren;
        for (int i = 0; i < size; ++i) {
            final View child = children[i];
            if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
                measureChild(child, widthMeasureSpec, heightMeasureSpec);
            }
        }
    }
就是遍历所有的children,当不是GONE时调用measureChild方法...


最近开始看源码之后,发现以前好多看视频看书不知道的地方都可以直接理解了,大部分的教程都只会教你怎么调用而不告诉你原因,所以就学了忘,忘了再看,看了一遍又一遍,效率极低...


上面博客有什么错误的地方希望大家指正,有不理解的可以一起交流大笑


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:3672次
    • 积分:106
    • 等级:
    • 排名:千里之外
    • 原创:7篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条