You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多层视图下ScrollView滚动时Toolbar隐藏后无法恢复的问题

解决Toolbar随ScrollView下滑无法滑入的问题

你遇到的问题在嵌套布局场景里很常见——当CoordinatorLayout和滚动View之间隔了多层布局时,普通ScrollView的滚动事件没法传递给AppBarLayout,导致设置了scroll|enterAlways的Toolbar只能上滑隐藏,却无法随下滑动作恢复。下面给你两种可行的解决方案:

方案一:替换为NestedScrollView(推荐,最简单)

NestedScrollView是AndroidX提供的支持嵌套滚动的组件,它会自动把滚动事件传递给CoordinatorLayout,完美适配AppBarLayout的滚动行为。只需要做几个小修改:

  1. 替换ScrollView为NestedScrollView
    把布局里的<ScrollView>换成<androidx.core.widget.NestedScrollView>,注意导入正确的AndroidX包。

  2. 给外层LinearLayout设置Behavior
    找到和AppBarLayout同级的那个LinearLayout(也就是CoordinatorLayout的直接子View),添加app:layout_behavior="@string/appbar_scrolling_view_behavior"属性,让CoordinatorLayout识别这个布局是滚动容器的父容器。

  3. 保留Toolbar的scrollFlags设置
    保持Toolbar的app:layout_scrollFlags="scroll|enterAlways"不变。

修改后的完整布局示例:

<androidx.coordinatorlayout.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">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <androidx.appcompat.widget.Toolbar
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:layout_scrollFlags="scroll|enterAlways"/>

    </com.google.android.material.appbar.AppBarLayout>

    <!-- 必须给这个LinearLayout设置behavior -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:src="@drawable/your_image"/>

            <androidx.core.widget.NestedScrollView
                android:layout_width="match_parent"
                android:layout_height="match_parent">

                <!-- 你的滚动内容容器 -->
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">
                    <!-- 这里放你的数字列表等滚动内容 -->
                </LinearLayout>

            </androidx.core.widget.NestedScrollView>

        </LinearLayout>

    </LinearLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

这样修改后,下拉NestedScrollView时,Toolbar就会平滑滑入,完全符合你想要的scroll|enterAlways效果。

方案二:自定义ScrollView传递滚动事件(如果必须用ScrollView)

如果因为某些限制不能替换成NestedScrollView,可以自定义一个ScrollView,手动把滚动事件传递给AppBarLayout的Behavior:

  1. 创建自定义ObservableScrollView
class ObservableScrollView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : ScrollView(context, attrs, defStyleAttr) {

    private var scrollListener: OnScrollChangeListener? = null

    override fun onScrollChanged(l: Int, t: Int, oldl: Int, oldt: Int) {
        super.onScrollChanged(l, t, oldl, oldt)
        scrollListener?.onScrollChanged(this, l, t, oldl, oldt)
    }

    fun setOnScrollChangeListener(listener: OnScrollChangeListener) {
        this.scrollListener = listener
    }

    interface OnScrollChangeListener {
        fun onScrollChanged(v: ObservableScrollView, scrollX: Int, scrollY: Int, oldScrollX: Int, oldScrollY: Int)
    }
}
  1. 在Activity中监听滚动并通知Behavior
    在你的Activity里,找到自定义ScrollView、AppBarLayout和CoordinatorLayout,手动转发滚动事件:
class YourActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.your_layout)

        val scrollView = findViewById<ObservableScrollView>(R.id.observable_scroll_view)
        val appBarLayout = findViewById<AppBarLayout>(R.id.app_bar_layout)
        val coordinatorLayout = findViewById<CoordinatorLayout>(R.id.coordinator_layout)

        scrollView.setOnScrollChangeListener { v, _, scrollY, _, oldScrollY ->
            // 获取AppBarLayout的Behavior实例
            val appBarParams = appBarLayout.layoutParams as CoordinatorLayout.LayoutParams
            val behavior = appBarParams.behavior as AppBarLayout.Behavior?
            
            // 手动触发嵌套滚动事件
            behavior?.onNestedScroll(
                coordinatorLayout,
                appBarLayout,
                v,
                0,
                scrollY - oldScrollY, // 滚动差值
                intArrayOf(0, 0),
                0
            )
        }
    }
}
  1. 同样设置外层LinearLayout的Behavior
    和方案一一样,确保和AppBarLayout同级的LinearLayout设置了app:layout_behavior="@string/appbar_scrolling_view_behavior",Toolbar的scrollFlags保持不变。

为什么之前的设置无效?

普通ScrollView没有实现嵌套滚动接口,它的滚动事件只会在自身内部处理,不会传递给上层的CoordinatorLayout。而你中间的两层LinearLayout也没有配置对应的滚动Behavior,导致CoordinatorLayout无法感知到ScrollView的下滑动作,自然不会触发Toolbar的enterAlways效果。

内容的提问来源于stack exchange,提问作者Cactus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:02:48