美文网首页
测量View(二):测量宽高及真实宽高

测量View(二):测量宽高及真实宽高

作者: MinicupSimon | 来源:发表于2017-08-16 16:14 被阅读0次

    测量View(一):创建View并测量 http://www.jianshu.com/p/4fb206b947ee
    测量View(三):获得测量宽高及真实宽高 http://www.jianshu.com/p/cbd758a5b5cf

    测量的宽高 与真实宽高 的区别

    很简单用ScrollView举例,当ScrollView中有很多内容一屏显示不全时,此时测量的高度(HorizontalScrollView宽度)是超过屏幕的高度(宽度)的,但是手机最终展示给用户时的真实宽高所占的尺寸最多不超过屏幕的尺寸。

    测量的宽高

    在正确获得View的宽高前,我们来分析一下原码

    view.getMeasuredWidth();
    view.getMeasuredHeight();
    

    View:getMeasuredWidth();

     public final int getMeasuredWidth() {
            return mMeasuredWidth & MEASURED_SIZE_MASK;
        }
    

    View:getMeasuredHeight();

        public final int getMeasuredHeight() {
            return mMeasuredHeight & MEASURED_SIZE_MASK;
        }
    

    以上返回的是该 View 的原始宽度和高度

    查看View对mMeasuredWidth及mMeasuredHeight的引用发现setMeasuredDimensionRaw方法对其进行赋值:

    private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) {
            mMeasuredWidth = measuredWidth;
            mMeasuredHeight = measuredHeight;
            mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;
    }
    

    回看调用顺序

        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;
            }
            setMeasuredDimensionRaw(measuredWidth, measuredHeight);
        }
    
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                    getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
        }
    

    以上这里看到了熟悉的方法onMeasure() ;

    小结:如果想得到measuredWidth 及measuredHeight 要调用 onMeasure() 即:measure()

    真实的宽高

    view.getWidth();
    view.getHeight();
    

    View:getWidth();

        public final int getWidth() {
            return mRight - mLeft;
        }
    

    View.getHeight();

        public final int getHeight() {
            return mBottom - mTop;
        }
    

    以上涉及到四个变量不难看出为View的坐标

    同样的方法找到几个相应的方法

    public final void setLeft(int left) {
            ...
            mLeft = left;
            ...
    }
    public final void setRight(int right) {
            ...
            mRight = right;
            ...
    }
    
    public final void setTop(int top) {
            ...
            mTop = top;
            ...
    }
    
    public final void setBottom(int bottom) {
            ...
            mBottom = bottom;
            ...
    }
    

    细心的朋友已经发现以上方法为final的
    而且查看注释发现:
    This method is meant to be called by the layout system and should not generally be called otherwise, because the property may be changed at any time by the layout.
    简单说就是该方法应由布局系统调用,不能随便调用

    继续找发现:

    
        protected boolean setFrame(int left, int top, int right, int bottom) {
                ...
                mLeft = left;
                mTop = top;
                mRight = right;
                mBottom = bottom;
                ...
        }
    
        /**
         * Same as setFrame, but public and hidden. For use in {@link android.transition.ChangeBounds}.
         * @hide
         */
        //与setFrame相同, 但是@hide被隐藏
        public void setLeftTopRightBottom(int left, int top, int right, int bottom) {
            setFrame(left, top, right, bottom);
        }
    
    
    public void layout(int l, int t, int r, int b) {
            ...
            boolean changed = isLayoutModeOptical(mParent) ? setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
            ...
    }
    
        //最终还是调用的setFrame()方法
        private boolean setOpticalFrame(int left, int top, int right, int bottom) {
            Insets parentInsets = mParent instanceof View ?
                    ((View) mParent).getOpticalInsets() : Insets.NONE;
            Insets childInsets = getOpticalInsets();
            return setFrame(
                    left   + parentInsets.left - childInsets.left,
                    top    + parentInsets.top  - childInsets.top,
                    right  + parentInsets.left + childInsets.right,
                    bottom + parentInsets.top  + childInsets.bottom);
        }
    

    以上又看到我们熟悉的方法

    要获得View的真实宽高,需要调用 layout()

    总结:

    getWidth(): View在设定好布局后的宽。
    getMeasuredWidth(): 对View测量后得到的测量宽度

    相关文章

      网友评论

          本文标题:测量View(二):测量宽高及真实宽高

          本文链接:https://www.haomeiwen.com/subject/efmirxtx.html