MeanStreet
MeanStreet

Reputation: 1287

Expand/Fold a Layout when user swipes

In an Android project, I have an Activity that contains (from top to bottom) a header, a RecyclerView and a RelativeLayout.

Code sample :

<android.support.design.widget.CoordinatorLayout ...>
    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        ...
    </android.support.design.widget.AppBarLayout>

    <android.support.v7.widget.RecyclerView 
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
        ...
    </RelativeLayout>

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

This is the behaviour I want : the RelativeLayout is "folded" by default, i.e. under the RecyclerView. When the user swipes up, the RelativeLayout expands to use the whole screen, and folded again when swipes down.

What is the right way to do it ? As I want the RelativeLayout to be BELOW the RecyclerView when folded, and OVER it when expanded. I tried setting the dependencies between elements dynamically but couldn't manage to do so.

Thanks for any help or advice on how to organize the activity to get such a behaviour.

EDIT

This is the XML structure :
<CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    </AppBarLayout>

    <RecyclerView
        android:id="@+id/top_list"   
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/app_bar"
        android:layout_above="@+id/relativelayout_footer" />

    <RelativeLayout
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:layout_alignParentBottom="true">
        <TextView ...>
        <RecyclerView 
            android:id="@+id/included_list"
            android:layout_height="match_parent"
            android:layout_width="match_parent"
            android:visibility="gone"/>
    </RelativeLayout>

</RelativeLayout>

</CoordinatorLayout>

And the listener :

    top_list.setVisibility(playlistOpened ? View.VISIBLE : View.GONE);
    app_bar.setVisibility(playlistOpened ? View.VISIBLE : View.GONE);
    included_list.setVisibility(playlistOpened ? View.GONE : View.VISIBLE);

    Transition cb = new ChangeBounds();
    cb.setDuration(1000);
    TransitionManager.beginDelayedTransition(slider, cb);

    playlistOpened = ! playlistOpened;

As you see, I switch the visibility of the elements in order to reorganise the view. When the included_list is set to VISIBLE, it pushes up the TextView.

The only problem is that the top_list and the app_bar disappear before being covered by the RelativeLayout. I tried adding a Listener to the Transition and do these when the transition ends, but it doesn't work (I guess because they're not set to GONE at the beginning, so the RelativeLayout can't move up). Any idea of how to do so ? Maybe I should open another question for it ?

Upvotes: 1

Views: 883

Answers (1)

kalabalik
kalabalik

Reputation: 3832

Okay, a final attempt. I am back to RelativeLayout and added another one around the RecyclerView to fix its scrolling problem. However, transitions get tricky (and the listener complicated) then. In order to prevent the RecyclerView from popping away before the RelativeLayout with the TextView inside fully covers the latter, I had to include a fading transition to the RecyclerView, too. Hope this suits you.

XML:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    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">

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

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <RelativeLayout
            android:id="@+id/rlwithrecyclerview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_above="@+id/rlwithtextview"
            android:layout_alignParentTop="true">

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

        <RelativeLayout
            android:id="@+id/rlwithtextview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="400dp"
                android:id="@+id/textview"
                android:text="Just a test" />
        </RelativeLayout>
    </RelativeLayout>
</android.support.design.widget.CoordinatorLayout>

onClick():

@Override
public void onClick(View v) {
    RelativeLayout rlWithRecyclerView = findViewById(R.id.rlwithrecyclerview);
    RelativeLayout.LayoutParams layoutParamsRlWithRecyclerView;

    RelativeLayout rlWithTextView = findViewById(R.id.rlwithtextview);
    RelativeLayout.LayoutParams layoutParamsRlWithTextView;

    if (rlWithTextView.getLayoutParams().height == MATCH_PARENT) {
        layoutParamsRlWithTextView = new RelativeLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT);
        layoutParamsRlWithRecyclerView = new RelativeLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT);
        layoutParamsRlWithRecyclerView.addRule(RelativeLayout.ALIGN_PARENT_TOP);
        layoutParamsRlWithRecyclerView.addRule(RelativeLayout.ABOVE, R.id.rlwithtextview);
    } else {
        layoutParamsRlWithRecyclerView = new RelativeLayout.LayoutParams(MATCH_PARENT, 0);
        layoutParamsRlWithTextView = new RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT);
    }
    layoutParamsRlWithTextView.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);

    Transition changeBounds = new AutoTransition();
    changeBounds.setDuration(500);
    TransitionManager.beginDelayedTransition(rlWithRecyclerView, changeBounds);
    TransitionManager.beginDelayedTransition(rlWithTextView, changeBounds);
    rlWithRecyclerView.setLayoutParams(layoutParamsRlWithRecyclerView);
    rlWithTextView.setLayoutParams(layoutParamsRlWithTextView);
}

Although I got credit for the two other answers, I will eventually delete them, since they don't solve the problem.

Upvotes: 1

Related Questions