Android AppBarLayout吸顶位置错误问题

在Android开发中,使用AppBarLayout实现复杂滚动和吸顶效果时,遇到隐藏子View后吸顶失效的问题。原因是AppBarLayout计算吸顶距离时不考虑View的可见性,导致实际可滚动距离增加。解决方法包括修改子View的LayoutParams高度或通过添加/移除View来避免影响AppBarLayout的scrollRange计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android AppBarLayout吸顶位置错误问题

我们通常会用AppBarLayout来做一些复杂滚动和吸顶的效果,比如如下代码:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/transparent">

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="btn1"
            app:layout_scrollFlags="scroll" />

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="btn2" />
    </android.support.design.widget.AppBarLayout>

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
            ...
        </LinearLayout>
    </android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>

正常展示的效果是这样的:
在这里插入图片描述
会在BTN2处吸顶,然后下面的NestedScrollView再进行滚动。

然而当我们将AppBarLayout里面的子View进行变动,比如在点击BTN1时,将BTN1隐藏掉(GONE),效果却变成了这样:
在这里插入图片描述
我们发现吸顶效果消失了,这是因为AppBarLayout计算scrollRange,即吸顶前可滚动的距离的方法,是不考虑View的可见性,而是直接加上View的measureHeight,而GONE掉的View的height是不会变的,只是不绘制而已,所以AppBarLayout实际可滚动的距离,就比我们预料的大了

public final int getTotalScrollRange() {
        if (this.totalScrollRange != -1) {
            return this.totalScrollRange;
        } else {
            int range = 0;
            int i = 0;

            for(int z = this.getChildCount(); i < z; ++i) {
                View child = this.getChildAt(i);
                AppBarLayout.LayoutParams lp = (AppBarLayout.LayoutParams)child.getLayoutParams();
                int childHeight = child.getMeasuredHeight();
                int flags = lp.scrollFlags;
                if ((flags & 1) == 0) {
                    break;
                }

                range += childHeight + lp.topMargin + lp.bottomMargin;
                if ((flags & 2) != 0) {
                    range -= ViewCompat.getMinimumHeight(child);
                    break;
                }
            }

            return this.totalScrollRange = Math.max(0, range - this.getTopInset());
        }
    }

结论:

  1. 如果需要GONE掉某个View,我们可以通过设置其LayoutParams的height或者通过addView/removeView操作实现,这样就不影响AppBarLayout的scrollRange计算

  2. 其他的View变动,比如addView,removeView等,由于都会自动重新测量而影响height计算,所以没问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值