Android CoordinatorLayout + AppbarLayout + Viewpag

2019-02-02 21:50发布

问题:

I have a classic layout with a ToolBar on the top, a TabLayout below it, and a ViewPager switching tabs from the TabLayout. When content in the ViewPager is scrollable, the ToolBar should scroll out of sight, and the TabLayout should follow and stick when it reaches the top.

All this is good in my current code, except, the ToolBar is always scrollable, regardless of the size of the ViewPager's content. See my code below. Any brilliant ideas on how to fix this?

<?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>

EDIT:

I can see that the viewPager's height is the same as the height for the entire root view. This might be intentded, as the appbar_scrolling_view_behavior does seem to add a top and bottom offset. It does however seem weird, since it will result in always scrolling the toolbar and tabbar.

回答1:

I suggested you try this sample.

this is a layout like your layout in the sample.

<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>


回答2:

I have solved the issue, tried over the example Google template and find out that

app:layout_behavior="@string/appbar_scrolling_view_behavior" 

line must be added into view pager properties xml. It solved my problem.



回答3:

using ListView as the data for ViewPager? If so, you need listView.setNestedScrollingEnabled(true);



回答4:

Try adding these attributes on TabLayout:

 app:layout_collapseMode="pin"
 app:tabMode="fixed"

And this on AppBarLayout:

 android:fitsSystemWindows="true"

* UPDATE *

I tried and this is not enough, since toolbar is still scrollable. The solution is to make some logic about ViewPager (and its content).

Remove from xml layout file the toolbar scroll_flag attribute. You have to implement some java code to check if ViewPager content height is > then screenHeight - (toolbar + tabBar). If true, set programmatically the scroll_flags as this:

 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);


回答5:

The ViewPager height should be match_parent and not wrap_content.



回答6:

Based on other samples, my own code, and the (somewhat messy) source code of the 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;
    }

I'm reading this in a way explaining the problem, as this is expected behavior with this code.

I think we need to write our own scroll behavior, specially for the RecyclerView,



回答7:

i've just had the same problem. The solution is very simple, just set your viewpager height

android:layout_height="wrap_content"


回答8:

Simple solution is - wrap your appbar layour and page viewer with a relative layout. - give your appbar layout some id - in page view set android:layout_below="Your_appbar_layout" Eg:

<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>