4

I have three different layouts cardsListLayout , titleLayout , cardMagazineLayoutand there may be more in the future, which used as a views on onCreateViewHolder method.

I want to switch between views in onCreateViewHolder method so when user choose from AlertDialog list

this onOptionsItemSelected in MainActivity Where there is menu Item "change the layout" so that when the user presses it it appears AlertDialog list

    @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
                            Toast.makeText(MainActivity.this,
                                    "Title layout", Toast.LENGTH_LONG).show();
                            break;
                        case 1: // Cards List
                            Toast.makeText(MainActivity.this,
                                    "Card list", Toast.LENGTH_LONG).show();
                            break;
                        case 2: // Cards Magazine Layout
                            Toast.makeText(MainActivity.this,
                                    "Card Magazine Layout", Toast.LENGTH_LONG).show();
                    }
                }
            });

and this my custom adapter class PostAdapter

public class PostAdapter extends RecyclerView.Adapter<PostAdapter.PostViewHolder> {
    private Context context;
    private List<Item> items;

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

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

// here's the three layouts that I can't switch between it

        View cardsListLayout = 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);

        return new PostViewHolder(titleLayout);
    }

    @Override
    public void onBindViewHolder(@NonNull PostViewHolder holder, int position) {
        final Item item = items.get(position);
        holder.postTitle.setText(item.getTitle());
        final Document document = Jsoup.parse(item.getContent());
        Elements elements = document.select("img");


        Log.e("CODE", "Image: " + elements.get(0).attr("src"));
//        Log.d("Text",document.text());
//        holder.postDescription.setText(document.text());

        Glide.with(context).load(elements.get(0).attr("src"))
                .into(holder.postImage);

        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(context, DetailsActivity.class);
                intent.putExtra("url", item.getUrl());
                intent.putExtra("title", item.getTitle());
                intent.putExtra("content", item.getContent());
                int youtubeThumbnailImagesetVisibility = 0;

                Element element = document.body();

                String youtubeThumbnailImageSrc = "";
                String youTubeLink = "";
                for (Element e : element.getElementsByClass
                        ("YOUTUBE-iframe-video")) {
                    youtubeThumbnailImageSrc = e.attr("data-thumbnail-src");
                    youTubeLink = e.attr("src");
                    Log.e("YouTube thumbnail", youtubeThumbnailImageSrc);
                    Log.e("Youtube link", youTubeLink);
                }

                if (youtubeThumbnailImageSrc.isEmpty()) {
                    youtubeThumbnailImagesetVisibility = 8;
                    intent.putExtra("youtubeThumbnailImagesetVisibility",
                            youtubeThumbnailImagesetVisibility);
                } else {
                    intent.putExtra("youtubeThumbnailImageSrc", youtubeThumbnailImageSrc);
                    intent.putExtra("youTubeLink", youTubeLink);
                }

//             String imageSrc = elements.get(0).attr("src");
//             intent.putExtra("blogImage",imageSrc);

                context.startActivity(intent);
            }
        });

    }

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

    public class PostViewHolder extends RecyclerView.ViewHolder {

        ImageView postImage;
        TextView postTitle;
        TextView postDescription;

        public PostViewHolder(View itemView) {
            super(itemView);
            postImage = itemView.findViewById(R.id.postImage);
            postTitle = itemView.findViewById(R.id.postTitle);
            postDescription = itemView.findViewById(R.id.postDescription);

        }
    }

}

I created two different Layout Manager for each one, there's a LinearLayoutManager and GridLayoutManager, currently I used GridLayout so I commented the LinearLayoutManger temporarily until I know how to switch between them

//      linearLayoutManager = new LinearLayoutManager(this);
        gridLayoutManager = new GridLayoutManager(this, 2, RecyclerView.VERTICAL, false);
//        recyclerView.setLayoutManager(linearLayoutManager);
        recyclerView.setLayoutManager(gridLayoutManager);

The result I aspire to

Dr Mido
  • 2,414
  • 4
  • 32
  • 72
  • 1
    Idea of adapter is not to recreate views when you don't need to. And adapter just checks the viewType that you need for your view at particular position. So if you want another layout to be created, then you need to tell adapter to notifyDataChanged and respond different view types through getItemViewType(position) that you want cells to be regenerated. – getKonstantin Mar 14 '19 at 21:24
  • @peregreen I think we can access `adapter.onCreateViewHolder` method from MainActivity , also there's `recyclerView.addOnLayoutChangeListener` What I would like to say is that the idea is not impossible, there are many applications that have this feature that allows to change the layout to another immediately when user choose another one – Dr Mido Mar 14 '19 at 21:35
  • in my case when user set grid layout, i set span count to 2 (or any number which you want ) and i list like objects i set span count to 1. – Masoom Badi Mar 15 '19 at 00:57
  • @sam I got What you mean, but this solution will not work if there's multiple different layouts, the `post_item_grid_layout` is contains different than `post_item_card_layout` – Dr Mido Mar 15 '19 at 02:57
  • @DrMido why dont you set new layout manager by calling custom `updatelayoutmethod` everytime when option is selected.. Provide a switch case inside the method and set layout as per.. – Masoom Badi Mar 15 '19 at 03:01
  • @Sam see the last updated with GIF to understand What I mean – Dr Mido Mar 15 '19 at 06:42
  • yea.. i got it.. have a look at this... https://stackoverflow.com/a/28735183/8809599 this is what i explained.. providing a switch case.. – Masoom Badi Mar 15 '19 at 07:43
  • @Sam yes I saw this question lately and I commented on it requested more details from him – Dr Mido Mar 15 '19 at 07:51
  • 1
    @DrMido I would not say it's impossible. I just said that viewType is intended in adapter for that. So rule of thumb: 1) You want different UI for cells: Then create a different viewTypes, 2) You want different layout (list or grid) for cells: then just change the layout manager. The answer that @Sam. mentioned with `isViewWithCatalog` will only work when there is 1 <-> 1 relationship with layout managers because they will not use cache of each other. But generally, that's not recommended approach. – getKonstantin Mar 15 '19 at 17:28

4 Answers4

5

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

Dr Mido
  • 2,414
  • 4
  • 32
  • 72
AskNilesh
  • 67,701
  • 16
  • 123
  • 163
  • thanks for answer, I copied all your code and I got `java.lang.ClassCastException: abtallaldigital.blogspot.com.dummyapp.PostAdapter$TitleListViewHolder cannot be cast to abtallaldigital.blogspot.com.dummyapp.PostAdapter$GridViewHolder` when I tried to change layout – Dr Mido Mar 20 '19 at 09:22
  • @DrMido you need to create 3 different `RecyclerView.ViewHolder` just like in my `DataAdapter` class check again it – AskNilesh Mar 20 '19 at 09:23
  • @DrMido please share your adpter class with questiion let me check your code – AskNilesh Mar 20 '19 at 09:26
  • @DrMido also make sure your returning correct `ViewHolder` class based on `VIEW_TYPE` inside `onCreateViewHolder()` method – AskNilesh Mar 20 '19 at 09:27
  • @DrMido I'm not able to reproduce your issue using your code for me it's working find can u please the same code as github repo – AskNilesh Mar 20 '19 at 15:03
  • no I still trying to know what is causing this exception – Dr Mido Mar 21 '19 at 11:25
  • @DrMido can u share the same code as github repo so i can reproduced the issue – AskNilesh Mar 21 '19 at 11:30
  • @DrMido thanks let me know when u create repository – AskNilesh Mar 21 '19 at 11:34
  • I solved the problem and I knew Why this `ClassCastException` happens because you forget to add `if (holder instanceof ...Holder)` before casting, this working for me – Dr Mido Mar 21 '19 at 19:21
3

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

MML
  • 44
  • 1
  • 8
  • 21
  • This should work, but I don't see where you account for the current scroll position before and after changing the recycler view. Also I think you could achieve this using just one Recycler view, I'll try it out and post my results. – Peterstev Uremgba Mar 19 '19 at 09:29
  • Sorry I could not comment there because my reputation is deducted yesterday to under 50, however, I saw other [question](https://stackoverflow.com/q/28581712/7639296) about this issue and I tried to make the trick with one RecyclerView as explained in some answers but this caused mixed layout when scrolling, and made the view look ugly,There's no problem using the ViewFlipper with three layout each one with RecylerView. This does not cause any overload or hanging the app. I think it is designed for this purpose. – MML Mar 19 '19 at 09:47
2

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.

sourav.bh
  • 467
  • 1
  • 7
  • 20
  • hi sourav.bh, thanks for answer, but unfortunately using this way cause mixed between layout when I scrolling I see some of item is with old layout, I tried to call `adapter.notifyDataSetChanged();` but also didn't effected – Dr Mido Mar 17 '19 at 08:44
  • Sorry, I missed to mention that every time you called `updateViewType` method you should also need to call `notifyDataSetChanged`. And I found a flaw in my answer, you should compare the viewType you found inside the adapter methods. I was comparing against the `currentViewType` variable, that was not correct. Please see my edited answer. – sourav.bh Mar 17 '19 at 08:56
  • @DrMido did you tried the updated answer? or it is still not working? – sourav.bh Mar 18 '19 at 03:56
  • 1
    @sourav.bh your answer looks right, but I would avoid inflating all 3 layouts in onCreateViewHolder if you use just one. Much better to inflate the needed one when you already checked the type. Plus looks like you're still comparing against ```currentViewType``` in the second case for ```VIEW_TYPE_GRID``` – getKonstantin Mar 18 '19 at 05:33
  • yes, you don't need to inflate all three layouts there. I just used the code you mentioned and wanted to make you comfortable the logic first. I apologies for the refactoring issues, I was editing from mobile web yesterday and that was quite shaky. Anyway, I am reviewing the code now and will update accordingly. And if it works for you then please consider to mark it as accepted so that others can be benefited too. – sourav.bh Mar 18 '19 at 06:03
  • @sourav.bh unfortunately I still showing mixed layouts on scrolling – Dr Mido Mar 18 '19 at 07:41
  • @Dr Mido please check my answer – MML Mar 18 '19 at 07:47
  • @DrMido, sorry to hear that. Please allow me some time, so that I can actually try the solution for myself. – sourav.bh Mar 18 '19 at 08:03
  • @DrMido, I have finally tested, fixed and updated my answer. Please see my detailed notes at the bottom of the answer and try accordingly. I believe this should solve your problem without any further hassle. Happy coding. – sourav.bh Mar 21 '19 at 19:49
0

Don't Do Longer. Just Change the layout of recyclerview on alertdialog click. If you want to use grid layout than change it to the grid layout, LinearLayout and set adapter.notifydatasetchanged, And if you want to change the layout of recyclerview Adapter row than Add a parameterized constructor to the adapter of recyclerview.After that Read the parameters and set views according to that.like this

 public CategoryRecyclerview(List<MainCategory> mainCategories, Context context, FragmentManager fragmentManager,String layouttype) {
    this.context = context;
    layouttype= this.layouttype;}

and in the oncreateviewholder put this

 if(layouttype.equals("GRID")){
        View view = inflater.inflate(R.layout.grid, viewGroup, false);
        CategoryRecyclerview.Myviewholder viewHolder = new CategoryRecyclerview.Myviewholder(view);
        holders.add(viewHolder);
        return viewHolder;
    }

after that notifydatasetchanged.

raj kavadia
  • 926
  • 1
  • 10
  • 30