自定义View中的onMeasure,measureChild与measureChildren

在重写的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方法...


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


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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值