Shumin Gao
Shumin Gao

Reputation: 697

CoordinatorLayout not working well with NestedScrollView and viewpager

Recently, I used Android Design Support Library and I have the following code for my collapsing toolbar.

<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:id="@+id/media_detail_appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        >

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"
            app:contentScrim="?attr/colorPrimary"
            >

            <include
                layout="@layout/layout_card"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                />

            <android.support.v7.widget.Toolbar
                android:id="@+id/media_detail_toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                app:layout_collapseMode="pin"
                />

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

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

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        >

        <android.support.design.widget.TabLayout
            android:id="@+id/media_detail_tabs"
            android:layout_width="match_parent"
            android:layout_height="?android:attr/actionBarSize"
            android:background="@color/blue_2"
            app:tabMode="scrollable"
            />

        <android.support.v4.view.ViewPager
            android:id="@+id/view_pager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            />

    </LinearLayout>

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

I have two fragments for the View Pager. One is NestedScrollView and the other is Recycler View. My issue is the NestedScrollView, here's the code below.

<android.support.v4.widget.NestedScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    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>
</android.support.v4.widget.NestedScrollView>

My issue is that when you scroll the view up, as soon as your finger moves a bit on the side, it triggers the horizontal scroll for the view pager. Could you please help me to avoid that ? When we scroll up and down, the view pager shouldn't be triggered. It works well in my recycler view fragment. Thanks.

Upvotes: 11

Views: 2172

Answers (2)

MarkoR
MarkoR

Reputation: 553

Best solution I came up with so far for this issue, is to track touch events and figure out when user scrolled vertically, and then to disable ViewPager scrolling until user lifts finger off the screen.

Add this to your activity:

private float startX;
private float startY;

@Override
public boolean dispatchTouchEvent(MotionEvent event)
{
    if (event.getAction() == MotionEvent.ACTION_DOWN)
    {
        startX = event.getX();
        startY = event.getY();
    }
    else if (event.getAction() == MotionEvent.ACTION_MOVE &&
        Math.abs(event.getX() - startX) < Math.abs(event.getY() - startY) &&
        Math.abs(event.getY() - startY) > 20)
    {
        ViewPager viewPager = findViewById(R.id.view_pager);
        viewPager.requestDisallowInterceptTouchEvent(true);
    }

    return super.dispatchTouchEvent(event);
}

Couple remarks:

  • requestDisallowInterceptTouchEvent disallows ViewPager to intercept touch events just until user lifts finger off the screen, after that it will normally work if user starts scrolling horizontally to change tabs.
  • 20 is threshold for vertically scrolled distance that I found works the best, feel free to change.

Upvotes: 0

GPack
GPack

Reputation: 2504

I tried same layout with the latest version of these libraries

compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.android.support:design:23.1.1'

and it works well as expected, that is:

if the gesture is mainly vertical scroll (even diagonal) NestedScrollView triggers the scroll, otherwise if the gesture is mainly horizontal swipe (even with a minimal vertical gap) ViewPager triggers the swipe. To solve upgrade your libraries.

Upvotes: 1

Related Questions