Android CoordinatorLayout + AppbarLayout + Viewpager 总是滚动

28

我有一个经典的布局,顶部有一个工具栏(ToolBar),下面是一个TabLayout,ViewPager通过切换选项卡来显示内容。当ViewPager中的内容可以滚动时,ToolBar应该向上滚动消失,TabLayout也应该跟随并停留在顶部。

目前我的代码已实现以上功能,但无论ViewPager的内容大小如何,ToolBar都是可滚动的。请参考下方代码,是否有任何好的想法来解决这个问题?

<?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:orientation="vertical">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/primary"
        android:orientation="vertical">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/AppTheme.ToolBar"
            app:layout_scrollFlags="scroll|enterAlways" />

        <android.support.design.widget.TabLayout
            android:id="@+id/tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="?attr/colorPrimary"
            android:scrollbars="horizontal"
            app:tabIndicatorColor="@color/black_text" />

    </android.support.design.widget.AppBarLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/tabs_activity_view_pager"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

</android.support.design.widget.CoordinatorLayout>

编辑:

我可以看到viewPager的高度与整个根视图的高度相同。这可能是有意为之的,因为appbar_scroll_view_behavior似乎确实添加了顶部和底部偏移量。但是这似乎很奇怪,因为它将导致工具栏和选项卡栏始终滚动。


你能更好地解释一下这个问题吗:“工具栏应该滚动消失”和“工具栏始终可滚动”,我不明白搜索结果是什么。 - lubilis
当ViewPager中的内容可以滚动并且被滚动时的结果:选项卡固定在顶部,工具栏被滚出。当ViewPager中的内容不可滚动时的结果:工具栏在顶部,选项卡在下方。 - Kenneth
2
当ViewPager的内容不可滚动时,移除app:layout_behavior="@string/appbar_scrolling_view_behavior"。 - tiny sunlight
你找到解决这个问题的好方法了吗?我也遇到了同样的问题。 - saturov
8个回答

8
我已经解决了这个问题,尝试了Google模板示例并找出了答案。
app:layout_behavior="@string/appbar_scrolling_view_behavior" 

必须将该行代码添加到view pager属性xml中。这解决了我的问题。


7

我建议您尝试这个示例。

这是一个类似于示例中的布局。

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
            app:layout_scrollFlags="scroll|enterAlways" />

        <android.support.design.widget.TabLayout
            android:id="@+id/tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </android.support.design.widget.AppBarLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end|bottom"
        android:layout_margin="@dimen/fab_margin"
        android:src="@drawable/ic_done" />

</android.support.design.widget.CoordinatorLayout>

1
这基本上就是我已经有的,而且它有同样的问题..? - Kenneth
这个示例是针对您的问题的教程。您可以使用示例模式来实现您的布局。 - Mohammad Hossein Gerami
请看下面的答案。示例项目有同样的问题。https://www.dropbox.com/s/16fep4r7linjtnp/sameproblem.mov?dl=0 - Kenneth
这个示例来自Google,因此我认为这种行为正是Google对Coordinate Layout的期望。换句话说,CoordinateLayout遵循Material Design的设计风格。如果你想要经典的滚动方式,那么你应该考虑使用RelativeLayout。 - SnowWolf

3

需要将ListView作为ViewPager的数据源吗?如果是,你需要使用 listView.setNestedScrollingEnabled(true);


0

基于其他示例、我的代码以及(有些混乱的)appbar_scrolling_view_behavior源代码:

        public boolean onDependentViewChanged(CoordinatorLayout parent, View child,
            View dependency) {
        final CoordinatorLayout.Behavior behavior =
                ((CoordinatorLayout.LayoutParams) dependency.getLayoutParams()).getBehavior();
        if (behavior instanceof Behavior) {
            // Offset the child so that it is below the app-bar (with any overlap)

            final int appBarOffset = ((Behavior) behavior)
                    .getTopBottomOffsetForScrollingSibling();
            final int expandedMax = dependency.getHeight() - mOverlayTop;
            final int collapsedMin = parent.getHeight() - child.getHeight();

            if (mOverlayTop != 0 && dependency instanceof AppBarLayout) {
                // If we have an overlap top, and the dependency is an AppBarLayout, we control
                // the offset ourselves based on the appbar's scroll progress. This is so that
                // the scroll happens sequentially rather than linearly
                final int scrollRange = ((AppBarLayout) dependency).getTotalScrollRange();
                setTopAndBottomOffset(AnimationUtils.lerp(expandedMax, collapsedMin,
                        Math.abs(appBarOffset) / (float) scrollRange));
            } else {
                setTopAndBottomOffset(dependency.getHeight() - mOverlayTop + appBarOffset);
            }
        }
        return false;
    }

我正在以一种解释问题的方式阅读这篇文章,因为这是使用此代码时预期的行为。

我认为我们需要为RecyclerView编写自己的滚动行为。


肯尼斯,能否发布代码'appbar_scrolling_view_behavior'? - Hiren Dabhi

0
尝试在TabLayout上添加这些属性:
 app:layout_collapseMode="pin"
 app:tabMode="fixed"

关于AppBarLayout的内容:

 android:fitsSystemWindows="true"

* 更新 *

我试过了,但这还不够,因为工具栏仍然可以滚动。 解决方案是对ViewPager(及其内容)进行一些逻辑处理。

从xml布局文件中删除工具栏scroll_flag属性。 您需要实现一些Java代码来检查ViewPager内容高度是否大于屏幕高度 - (工具栏+选项卡)。 如果是真的,以编程方式设置滚动标志如下:

 LayoutParams params;
 params = // get layout params from your toolbar

 params.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL
| AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS);

 // set params
 toolbar.setLayoutParams(params);

好的,现在我明白了,请尝试使用我的更新答案。 也许ViewPager应该有android:layout_height="match_parent"吗? - lubilis
呵呵。我试了你更新后的答案,也在ViewPager上使用了match_parent。但是还是没有成功,我很担心这可能无法实现。 - Kenneth
ViewPager内容片段包含ScrollView、ListView还是RecyclerView? - lubilis
抱歉,我一直很忙。很快会发布详细信息。 - Kenneth
1
我也想知道 :) - kiddouk
显示剩余6条评论

-1

ViewPager 的高度应该是 match_parent 而不是 wrap_content


1
谢谢,但这并没有改变任何事情。 - Kenneth

-2
简单的解决方案是: - 使用相对布局包装您的AppBar Layout和Page Viewer。 - 给您的AppBar Layout一些id。 - 在Page View中设置android:layout_below="Your_appbar_layout",例如:
<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

<android.support.design.widget.AppBarLayout
    android:id="@+id/your_appBar_ID"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/primary"
    android:orientation="vertical">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.ToolBar"
        app:layout_scrollFlags="scroll|enterAlways" />

    <android.support.design.widget.TabLayout
        android:id="@+id/tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        android:scrollbars="horizontal"
        app:tabIndicatorColor="@color/black_text" />

</android.support.design.widget.AppBarLayout>

<android.support.v4.view.ViewPager
    android:id="@+id/tabs_activity_view_pager"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_below="@+id/your_appBar_ID"
    app:layout_behavior="@string/appbar_scrolling_view_behavior" />

</RelativeLayout>


-2

我刚遇到了同样的问题。 解决方案非常简单,只需设置您的ViewPager高度即可

android:layout_height="wrap_content"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接