Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: Scrolling issues with recyclerview inside a viewpager

I have a RecyclerView inside a ViewPager that only occupies the bottom half of the screen, and what I want to do is have the entire screen scroll if the RecyclerViews received a vertical scroll event.

UI hierarchy in a nutshell:

CoordinatorLayout 
   --- AppBarLayout
       --- Toolbar
       --- Bunch of static LinearLayouts, occupy most of screen
       --- TabLayout
   --- ViewPager
       --- Fragments with RecyclerView

What I have: What I have

To my understanding, a RecyclerView is memory-efficient and tries to fit itself in whatever space is available in the screen. In my app, I have a ViewPager hosting multiple tabs, each of which have a RecyclerView to display different things.

Could you please give me some ideas of what I could do to make the whole screen scroll? I'm guessing the best shot is to add a CollapsingToolbarLayout with parallax to the static content in the middle of the screen. I even tried to do this, but the UI was completely broken. It's difficult since I only want the content in the middle of the screen to scroll out, not the toolbars on top. I didn't have much luck with a NestedScrollView either, apparently its compatibility with ViewPager and CoordinatorLayout is not straight-forward..

What I want: What I want

Main Activity Layout:

<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"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        >

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar_contributor"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:focusableInTouchMode="true">

            <android.support.v7.widget.SearchView
                android:id="@+id/searchview_contributor"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:icon="@drawable/ic_search_white_24dp"
                app:defaultQueryHint="Bla bla"
                app:iconifiedByDefault="false"/>

            <ImageButton
                android:layout_width="24dp"
                android:layout_height="24dp"
                android:background="@android:color/transparent"
               android:src="@drawable/ic_person_outline_black_24dp"/>

        </android.support.v7.widget.Toolbar>

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

            <Button
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight=".5"
                android:text="La Bla"/>

            <Button
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight=".5"
                android:text="Bla Bla"/>
        </LinearLayout>

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

            <!-- Bunch of stuff, but irrelevant -->

            <android.support.design.widget.TabLayout
                android:id="@+id/tablayout_profile"
                android:layout_width="match_parent"
                android:layout_height="40dp"/>
        </LinearLayout>

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

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

The fragment inside the Viewpager:

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerview_photos"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</FrameLayout>

Thanks in advance!

Update: The responses I received here (for which I am thankful) came a bit too late. If anyone knows which is the correct answer, please let me know!

like image 634
not_this_again Avatar asked Jan 29 '16 10:01

not_this_again


2 Answers

public class CustomRecyclerView extends RecyclerView {
public CustomRecyclerView(Context context) {
    super(context);
}

public CustomRecyclerView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public CustomRecyclerView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

int lastEvent = -1;

boolean isLastEventIntercepted = false;
private float xDistance, yDistance, lastX, lastY;

@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
    switch (e.getAction()) {
        case MotionEvent.ACTION_DOWN:
            xDistance = yDistance = 0f;
            lastX = e.getX();
            lastY = e.getY();

            break;

        case MotionEvent.ACTION_MOVE:
            final float curX = e.getX();
            final float curY = e.getY();
            xDistance += Math.abs(curX - lastX);
            yDistance += Math.abs(curY - lastY);
            lastX = curX;
            lastY = curY;

            if (isLastEventIntercepted && lastEvent == MotionEvent.ACTION_MOVE) {
                return false;
            }

            if (xDistance > yDistance) {

                isLastEventIntercepted = true;
                lastEvent = MotionEvent.ACTION_MOVE;
                return false;
            }
    }

    lastEvent = e.getAction();

    isLastEventIntercepted = false;
    return super.onInterceptTouchEvent(e);
}

}

Just change your recyclerview by this .

like image 100
nadafafif Avatar answered Sep 25 '22 13:09

nadafafif


I've done something very similar to this with a CollapsingToolbarLayout.

The trick here is to have two toolbars, one at the top with the searchview and another that is the toolbar dedicated to the collapsing layout.

Your searchview toolbar will have app:collapseMode="pin".

Your button bar will have app:collapseMode="pin".

Your LinearLayout below the button bar will have the default collapse mode so it will scroll. You can even give it a parallax effect with app:collapseMode="parallax".

Your TabLayout will have app:collapseMode="pin" so it scrolls up under the button bar and pins there.

Your ViewPager should be outside the CollapsingToolbarLayout and have the attribute app:layout_behavior="@string/appbar_scrolling_view_behavior".

The CollapsingToolbarLayout will want to display a title. Just call setTitle(null) on the collapsing toolbar and set your real title on the searchview toolbar.

You can put your navigation and menus on either the searchview toolbar and the collapsing toolbar and they should work as expected.

I will post some XML later; I just wanted to get this answer started.

like image 38
kris larson Avatar answered Sep 25 '22 13:09

kris larson