Switch between RecyclerView layouts when click on AlertDialog item list

To prevent mixed layout when scrolling you should use ViewFlipper with three different RecyclerView's , meaning RecyclerView for each layout.

Step 1:

  • Create a public enum for the three layouts
public enum ViewType {
    CARD_LIST_LAYOUT, TITLE_LAYOUT, CARD_MAGAZINE_LAYOUT;
}
  • In PostAdapter create a ViewType variable and pass it into constructor, and checking via if & else on onCreateViewHolder to know Which layout choosed
PostAdapter(Context context, List<Item> items, ViewType viewType) {
        this.context = context;
        this.items = items;
        this.viewType = viewType;
    }



    @NonNull
    @Override
    public PostAdapter.PostViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(context);

        View cardListLayout = inflater.inflate(R.layout.post_item_card_layout, parent, false);
        View titleLayout = inflater.inflate(R.layout.post_item_grid_layout, parent, false);
        View cardMagazineLayout = inflater.inflate(R.layout.card_magazine_layout, parent, false);

        if (this.viewType == ViewType.TITLE_LAYOUT) {
            return new PostViewHolder(titleLayout);
        } else if (this.viewType == ViewType.CARD_LIST_LAYOUT) {
            return new PostViewHolder(cardListLayout);
        } else {
            return new PostViewHolder(cardMagazineLayout);
        }
    }

Step 2:

  • Create a ViewFlipper in the class that contains the main RecyclerView, with three child's Layout's and RecyclerView's
<ViewFlipper xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/parentLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    >


        <LinearLayout
            android:id="@+id/linearLayout1"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/titleRecyclerView"
                android:layout_width="match_parent"
                android:layout_height="match_parent"

                >

            </androidx.recyclerview.widget.RecyclerView>

        </LinearLayout>


        <LinearLayout
            android:id="@+id/linearLayout2"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/cardRecyclerView"
                android:layout_width="match_parent"
                android:layout_height="match_parent"

                >


            </androidx.recyclerview.widget.RecyclerView>

        </LinearLayout>


        <LinearLayout
            android:id="@+id/linearLayout3"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/cardMagazineRecyclerView"
                android:layout_width="match_parent"
                android:layout_height="match_parent"

                >

            </androidx.recyclerview.widget.RecyclerView>


        </LinearLayout>

    </RelativeLayout>

</ViewFlipper>
  • In MainActivity define variable's like this
         viewFlipper = ((ViewFlipper) findViewById(R.id.parentLayout));


        titleRecyclerView = (RecyclerView) findViewById(R.id.titleRecyclerView);
        cardRecyclerView = (RecyclerView) findViewById(R.id.cardRecyclerView);
        cardMagazineRecyclerView = (RecyclerView) findViewById(R.id.cardMagazineRecyclerView);



        linearLayoutManager1 = new LinearLayoutManager(this);
        cardRecyclerView.setLayoutManager(linearLayoutManager1);
        linearLayoutManager2 = new LinearLayoutManager(this);
        cardMagazineRecyclerView.setLayoutManager(linearLayoutManager2);

        gridLayoutManager = new GridLayoutManager(this, 2, RecyclerView.VERTICAL, false);
        titleRecyclerView.setLayoutManager(gridLayoutManager);


        adapter1 = new PostAdapter(this, items, ViewType.TITLE_LAYOUT);
        titleRecyclerView.setAdapter(adapter1);
        adapter2 = new PostAdapter(this, items, ViewType.CARD_LIST_LAYOUT);
        cardRecyclerView.setAdapter(adapter2);
        adapter3 = new PostAdapter(this, items, ViewType.CARD_MAGAZINE_LAYOUT);
        cardMagazineRecyclerView.setAdapter(adapter3);
  • add ScrollListener for each RecyclerView
titleRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                if (newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {

                }

            }

            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if (dy > 0) {

                }

            }  
        });

cardRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                if (newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {

                }

            }

            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if (dy > 0) {

                }

            }  
        });

cardMagazineRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                if (newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {

                }

            }

            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if (dy > 0) {

                }

            }  
        });

Step 3:

  • And finally on onOptionsItemSelected switch between three layout when click
@Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.change_layout) {
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle(getString(R.string.choose_layout));

            String[] layouts = {"Title Layout", "Cards List", "Card Magazine Layout"};
            builder.setItems(layouts, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int index) {
                    switch (index) {
                        case 0: // Title layout
                            viewFlipper.setDisplayedChild(0);

                            break;
                        case 1: // Cards List Layout
                            viewFlipper.setDisplayedChild(1);
                            break;
                        case 2: // Cards Magazine Layout
                            viewFlipper.setDisplayedChild(2);
                    }
                }
            });

            AlertDialog dialog = builder.create();
            dialog.show();
            return true;
        }

[Important Note] you should doing any implementation of the old main RecyclerView three times each one for every layout or RecyclerView like the above example of ScrollListener.

Hope this working with you, and please inform me if you have any inquiries


No need to use multiple Recyclerview for this

You can achieve this using single Recyclerview with Multiple viewType

When you want to change the layout of Recyclerview just change the LayoutManager and viewType of your Recyclerview it will work

SAMPLE CODE

Try this way

First Create a Three layout for your Multiple viewType

grid_layout

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="150dp"
    android:layout_height="150dp"
    app:cardElevation="10dp"
    app:cardUseCompatPadding="true">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="150dp"
            android:adjustViewBounds="true"
            android:contentDescription="@string/app_name"
            android:scaleType="centerCrop"
            android:src="@drawable/dishu" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:background="#6a000000"
            android:gravity="center"
            android:padding="10dp"
            android:text="dummy text"
            android:textColor="@android:color/white" />
    </RelativeLayout>

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

cardlist_layout

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView 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="wrap_content"
    app:cardElevation="10dp"
    app:cardUseCompatPadding="true">

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

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="150dp"
            android:adjustViewBounds="true"
            android:contentDescription="@string/app_name"
            android:scaleType="centerCrop"
            android:src="@drawable/dishu" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingStart="5dp"
            android:paddingEnd="10dp"
            android:text="Dummy Title"
            android:textColor="@android:color/black"
            android:textStyle="bold" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingStart="5dp"
            android:paddingEnd="10dp"
            android:text="Dummy Tex" />


    </LinearLayout>
</android.support.v7.widget.CardView>

title_layout

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView 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="wrap_content"
    app:cardElevation="10dp"
    app:cardUseCompatPadding="true">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center">

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:orientation="vertical">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:paddingStart="5dp"
                android:paddingEnd="5dp"
                android:text="dummy text"
                android:textColor="@android:color/black"
                android:textStyle="bold" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="start"
                android:paddingStart="5dp"
                android:paddingEnd="5dp"
                android:text="I have three different layouts cardsListLayout , titleLayout , cardMagazineLayoutand there may be more in the future, which used as a views on onCreateViewHolder method." />
        </LinearLayout>

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="150dp"
            android:adjustViewBounds="true"
            android:contentDescription="@string/app_name"
            android:scaleType="centerCrop"
            android:src="@drawable/dishu" />


    </LinearLayout>
</android.support.v7.widget.CardView>

DataAdapter

package neel.com.recyclerviewdemo;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class DataAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    public static final int ITEM_TYPE_GRID = 0;
    public static final int ITEM_TYPE_CARD_LIST = 1;
    public static final int ITEM_TYPE_TITLE_LIST = 2;
    private Context mContext;
    private int VIEW_TYPE = 0;

    public DataAdapter(Context mContext) {
        this.mContext = mContext;
    }

    public void setVIEW_TYPE(int viewType) {
        VIEW_TYPE = viewType;
        notifyDataSetChanged();
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = null;
        // check here the viewType and return RecyclerView.ViewHolder based on view type
        switch (VIEW_TYPE) {
            case ITEM_TYPE_GRID:
                // if VIEW_TYPE is Grid than return GridViewHolder
                view = LayoutInflater.from(mContext).inflate(R.layout.grid_layout, parent, false);
                return new GridViewHolder(view);
            case ITEM_TYPE_CARD_LIST:
                // if VIEW_TYPE is Card List than return CardListViewHolder
                view = LayoutInflater.from(mContext).inflate(R.layout.cardlist_layout, parent, false);
                return new CardListViewHolder(view);
            case ITEM_TYPE_TITLE_LIST:
                // if VIEW_TYPE is Title List than return TitleListViewHolder
                view = LayoutInflater.from(mContext).inflate(R.layout.title_layout, parent, false);
                return new TitleListViewHolder(view);
        }
        return new GridViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        final int itemType = getItemViewType(position);
        // First check here the View Type
        // than set data based on View Type to your recyclerview item
        if (itemType == ITEM_TYPE_GRID) {
        if (holder instanceof CardViewHolder) {
            GridViewHolder viewHolder = (GridViewHolder) holder;
            // write here code for your grid list
      }
        } else if (itemType == ITEM_TYPE_CARD_LIST) {
       if (holder instanceof CardViewHolder) {
            CardListViewHolder buttonViewHolder = (CardListViewHolder) holder;
            // write here code for your grid list
       }
        } else if (itemType == ITEM_TYPE_TITLE_LIST) {
            if (holder instanceof CardViewHolder) {
            TitleListViewHolder buttonViewHolder = (TitleListViewHolder) holder;
            // write here code for your TitleListViewHolder
          }
        }
    }

    @Override
    public int getItemCount() {
        return 40;
    }

    // RecyclerView.ViewHolder class for gridLayoutManager
    public class GridViewHolder extends RecyclerView.ViewHolder {

        public GridViewHolder(@NonNull View itemView) {
            super(itemView);
        }
    }

    // RecyclerView.ViewHolder class for Card list View
    public class CardListViewHolder extends RecyclerView.ViewHolder {

        public CardListViewHolder(@NonNull View itemView) {
            super(itemView);
        }
    }

    // RecyclerView.ViewHolder class for Title list View
    public class TitleListViewHolder extends RecyclerView.ViewHolder {

        public TitleListViewHolder(@NonNull View itemView) {
            super(itemView);
        }
    }
}

MainActivity

package neel.com.recyclerviewdemo;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;

public class MainActivity extends AppCompatActivity {

    DataAdapter dataAdapter;
    private RecyclerView myRecyclerView;
    private LinearLayoutManager linearLayoutManager;
    private GridLayoutManager gridLayoutManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        myRecyclerView = findViewById(R.id.myRecyclerView);
        myRecyclerView.setHasFixedSize(true);

        linearLayoutManager = new LinearLayoutManager(this);
        gridLayoutManager = new GridLayoutManager(this, 3);

        myRecyclerView.setLayoutManager(gridLayoutManager);

        dataAdapter = new DataAdapter(this);
        myRecyclerView.setAdapter(dataAdapter);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.home_menu, menu);
        // return true so that the menu pop up is opened
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        if (item.getItemId() == R.id.action_dialog) {
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle("Please choose a layout");

            String[] layouts = {"Title Layout", "Cards List", "Grid View"};
            builder.setItems(layouts, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int index) {
                    switch (index) {
                        case 0: // Title layout
                            dataAdapter.setVIEW_TYPE(2);
                            myRecyclerView.setLayoutManager(linearLayoutManager);
                            myRecyclerView.setAdapter(dataAdapter);
                            break;
                        case 1: // Cards List
                            dataAdapter.setVIEW_TYPE(1);
                            myRecyclerView.setLayoutManager(linearLayoutManager);
                            myRecyclerView.setAdapter(dataAdapter);
                            break;
                        case 2: // Grid  Layout
                            dataAdapter.setVIEW_TYPE(0);
                            myRecyclerView.setLayoutManager(gridLayoutManager);
                            myRecyclerView.setAdapter(dataAdapter);
                    }
                }
            });

            builder.show();
        }
        return super.onOptionsItemSelected(item);
    }
}

activity_main layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
    tools:context=".MainActivity">

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

OUTPUT

https://youtu.be/L3slKTy2bzI


You can simply achieve this by implementing VIEW_TYPE inside your adapter. There is a overridden method in RecyclerView Adapter public int getViewType(int position), generally this method is used for mixing various types of views into a RecyclerView.

But you can use this in your case too. First define an enumeration of your view types. Then inside your adapter maintain a variable to store the current viewType, update that variable accordingly from the alert dialog item click.

Use that current viewType value into your onCreateViewHolder and onBindViewHolder methods to determine which layout you should use currently and which UI elements need to be updated now. Also update the RecyclerView layout manager from the alert dialog items on click.

public class PostAdapter extends RecyclerView.Adapter<PostAdapter.PostViewHolder> {

    public enum ViewType {
         VIEW_TYPE_GRID, VIEW_TYPE_CARD, VIEW_TYPE_CARD_MAGAZINE
    }

    private Context context;
    private List<Item> items;
    private ViewType currentViewType;

    public PostAdapter(Context context, List<Item> items, ViewType viewType) {
        this.context = context;
        this.items = items;
        this.currentViewType = viewType;
    }

    // Call this method from alert dialog item click.
    public void updateViewType(ViewType type) {
        this.currentViewType = type;
    }

    @Override
    public int getItemViewType(int position) {
        return this.currentViewType.ordinal();
    }

    @Override
    public int getItemCount() {
        return items.size();
    }

    @Override
    public PostAdapter.PostViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(context);

        // here's the layouts that you want to switch between, based on the viewType
        if (viewType == ViewType.VIEW_TYPE_CARD.ordinal()) {
            View cardLayout = inflater.inflate(R.layout. post_item_card_layout, parent, false);
            return new PostViewHolder(cardLayout);
        }
        else if (viewType == ViewType.VIEW_TYPE_GRID.ordinal()) {
            View gridLayout = inflater.inflate(R.layout. post_item_grid_layout,parent,false);
            return new PostViewHolder(gridLayout);
        }
        else {
            View cardMagazineLayout = inflater.inflate(R.layout. card_magazine_layout, parent, false);
            return new PostViewHolder(cardMagazineLayout);
        }
    }

    @Override
    public void onBindViewHolder(@NonNull PostViewHolder holder, int position) {
        final Item item = items.get(position);
        // Similarly handle different view layout items here based on the viewType returned from getItemViewType method.
        if (getItemViewType(position) == ViewType.VIEW_TYPE_CARD.ordinal()) {

        } else if (getItemViewType(position) == ViewType.VIEW_TYPE_GRID.ordinal()) {

        } else {

        }
    }
}

Update: Every time you called the updateViewType method you also need to call the notifyDataSetChanged method like this:

mAdapter.updateViewType(PostAdapter.ViewType.VIEW_TYPE_GRID);
mAdapter.notifyDataSetChanged()

*** I have tested this code on my device and it is working as expected. Please note that you should carefully handle the VIEW_TYPE when inflating layouts and using layout elements like TextView and ImageView. In my previous answer I have mixed up the view types with wrong layouts, that might be the only reason so that you have seen mixed layouts as output.

*** Also, the getItemViewType method was mistakenly renamed as getViewType and that was another culprit in my code which causes mixed output.