Search code examples
androidandroid-layoutandroid-fragmentsandroid-coordinatorlayout

Show/Hide LinearLayout when scrolling a RecyclerView?


I have a fragment loaded into my MainActivity. On top of the fragment's layout I have a LinearLayout which I would like to show/hide as the user scrolls up/down.

Can this be achieved using the Coordinator layout or I need to do my own hack?

layout.xml:

    <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:background="#ececec">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/discoverRView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:paddingLeft="5dp"
            android:paddingRight="5dp">

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


        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:background="#f00"
            app:layout_anchor="@+id/discoverRView"
            app:layout_anchorGravity="top"
            app:layout_scrollFlags="scroll"
            >

         </LinearLayout>



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

Solution

  • Maybe there are better solutions, but this can be achieved by creating a custom CoordinatorLayout.Behavior and adding it to a CustomLinearLayout:

    //This is taken from a project of mine, it scrolls a Layout up if a snackbar shows up. 
    
    public class MoveUpwardBehavior extends CoordinatorLayout.Behavior<View> {
    
        public MoveUpwardBehavior(){
            //super();
        }
    
        public MoveUpwardBehavior(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        @Override
        public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
            float translationY = Math.min(0, dependency.getTranslationY() - dependency.getHeight());
            child.setTranslationY(translationY);
            return true;
        }
    
        @Override
        public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
            return dependency instanceof Snackbar.SnackbarLayout;
        }
        @Override
        public void onDependentViewRemoved(CoordinatorLayout parent, View child, View dependency) {
            super.onDependentViewRemoved(parent, child, dependency);
            child.setTranslationY(0);
        }
    }
    

    You'll need a custom LinearLayout, but this part is easy peasy:

    @CoordinatorLayout.DefaultBehavior(MoveUpwardBehavior.class)
    public class CustomLinearLayout extends LinearLayout {
    
        public CustomLinearLayout(Context context) {
            super(context);
        }
    
        public CustomLinearLayout(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public CustomLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        public CustomLinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
        }
    }
    

    Surely, you'll need to use this layout in your xml:

    <com.your.project.CustomLinearLayout
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:background="#f00"
        app:layout_anchor="@+id/discoverRView"
        app:layout_anchorGravity="top">
        </com.your.project.CustomLinearLayout>
    

    So, I think you get the idea. You'll need to update the behaviour to depend on the scroll of your RecyclerView. If you need more help, I can try to build a working example.