ScrollView高度测量原理

博客探讨了ScrollView在高度设置为match_parent时仍能正常滚动的原因,主要在于ScrollView重写了ViewGroup的measureChildWithMargins方法,将子View的高度测量模式设为UNSPECIFIED。文章详细分析了四种不同情况下ScrollView及其子View的高度关系,并解释了MeasureSpec的作用和三种测量模式。此外,还提到了MeasureSpec与wrap_content、match_parent和固定值的关系。
摘要由CSDN通过智能技术生成

       在使用Lint扫描工程时,看到这个提示。 Google推荐将ScrollView的子View高度设置为wrap_content,  但实际业务开发时可能根节点是LinearLayout(layout_height="match_parent"), 然后发现屏幕显不下就包了一层ScrollView。 运行看到ScrollView能正常上下滑动,就没改LinearLayout的layout_height属性。

     为什么ScrollView仍然能上下滑动呢???  按照安卓View的测量方式LinearLayout应该跟ScrollView的高度相同。 去源码里找答案:ScrollView重写了ViewGroup的measureChildWithMargins方法, 该方法会在onMeasure里调用。

    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 usedTotal = mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin +
                heightUsed;
        final int childHeightMeasureSpec = MeasureSpec.makeSafeMeasureSpec(
                Math.max(0, MeasureSpec.getSize(parentHeightMeasureSpec) - usedTotal),
                MeasureSpec.UNSPECIFIED);
        //设置child高度的测量方式为UNSPECIFIED, 这也是ScrollView子View高度参数无效的原因。
        //UPSPECIFIED表示child高度由自己决定,不受父容器的限制
        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    }

   核心是设置child高度测量方式为UNSPECIFIED,  这就是为什么LinearLayout设置高度为match_parent仍然能够正常滑动的原因。  后面再讲为什么ScrollView要篡改子View高度的测量方式为UNSPECIFIED

     ScrollView和子View高度可以设置为wrap_content或者match_parent(与固定值高度情况相同)、 再考虑子View高度大于/小于ScrollView的高度,排列组合有8种情况。 上面说到给ScrollView的子View设置高度参数无效, 所以剩下4种情况。

 第一种情况:ScrollView高度是match_parent或固定值且子View高度小于ScrollView, 则子View高度是实际需要的高度。  如果需要子View高度等于父容器ScrollView, 则需要添加子View即LinearLayout属性android:fillViewPort="true"。

   @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //对应ScrollView的android:fillViewPort属性,默认值false
        if (!mFillViewport) {
            return;
        }
        //设置android:fillViewPort="true“后才会执行下面的代码
        final int heightMode 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值