ScrollView测量分析

ScrollView是继承FrameLayout,其对子view的测量比较怪异,因为其重写了FrameLayout中的几个测量方法

  @Override
  //scrollView重写的onMeasure方法
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //调用frameLayout的onMeasure方法进行测量,该方法会调用下面分析的measureChildWithMargins方法
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    //这个变量由scrollView的 android:fillViewport属性决定,默认是false
        if (!mFillViewport) {
            return;
        }
    //如果设置了android:fillViewport="true"会调用下面代码
    final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    //一般不等于MeasureSpec.UNSPECIFIED
        if (heightMode == MeasureSpec.UNSPECIFIED) {
            return;
        }

        if (getChildCount() > 0) {
        //对唯一的子view进行处理
            final View child = getChildAt(0);
            //获取自身高度
            int height = getMeasuredHeight();

            if (child.getMeasuredHeight() < height) {
            //如果测量出的子view高度小于自己,则执行下列代码,重新测量,其实就是当子view高度小于自身高度时,将子view高度设置为等于自身高度
                final FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();

                int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
                        mPaddingLeft + mPaddingRight, lp.width);
                height -= mPaddingTop;
                height -= mPaddingBottom;
                int childHeightMeasureSpec =
                        MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);

                child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
            }
        }
    }

另外ScrollView重写了ViewGroup的measureChildWithMargins方法(同时也重写了measureChild方法),这个方法会在super.onMeasure方法里面调用


   @Override
    protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed,
            int parentHeightMeasureSpec, int heightUsed) {
        final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
                mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
                        + widthUsed, lp.width);
       //这里是其重写关键,改变了高度的测量规格
        final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
                lp.topMargin + lp.bottomMargin, MeasureSpec.UNSPECIFIED);
    //然后才进行子view的测量,由于设置了MeasureSpec.UNSPECIFIED规格,会影响子view的测量
        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    }

总结

  • scrollView的子view高度属性android:layout_height设置无效,无论你设置为什么,其测量时会在measureChildWithMargins中将其变为MeasureSpec.UNSPECIFIED
  • 当设置 android:fillViewport属性为true时,如果测量的子view的高度小于scrollview自身的高度,则最终将子view设置为scrollview自身高度
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值