【问题标题】:Switch between RecyclerView layouts when click on AlertDialog item list单击 AlertDialog 项目列表时在 RecyclerView 布局之间切换
【发布时间】:2019-03-14 20:51:14
【问题描述】:

我有cardsListLayouttitleLayoutcardMagazineLayout三种不同的布局,未来可能还会有更多,用作onCreateViewHolder方法的视图。

我想在onCreateViewHolder 方法中的视图之间切换,所以当用户从 AlertDialog 列表中选择时

这个 onOptionsItemSelected in MainActivity 哪里有菜单项“改变布局”,这样当用户按下它就会出现AlertDialog列表

    @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();
                    }
                }
            });

这是我的自定义适配器类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);

        }
    }

}

我为每一个创建了两个不同的布局管理器,有一个 LinearLayoutManager 和一个 GridLayoutManager,目前我使用的是 GridLayout,所以我暂时评论了 LinearLayoutManger,直到我知道如何在它们之间切换

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

我渴望的结果

【问题讨论】:

  • 适配器的想法是不要在不需要时重新创建视图。适配器只是检查特定位置的视图所需的视图类型。因此,如果您想创建另一个布局,那么您需要告诉适配器 notifyDataChanged 并通过 getItemViewType(position) 响应不同的视图类型,您希望重新生成单元格。
  • @peregreen 我想我们可以从 MainActivity 访问adapter.onCreateViewHolder 方法,还有recyclerView.addOnLayoutChangeListener 我想说的是这个想法不是不可能的,有很多应用程序都有这个功能当用户选择另一个布局时,允许立即将布局更改为另一个布局
  • 在我的情况下,当用户设置网格布局时,我将跨度计数设置为 2(或您想要的任何数字)并列出我将跨度计数设置为 1 的对象。
  • @sam 我明白了你的意思,但是如果有多种不同的布局,这个解决方案将不起作用,post_item_grid_layout 包含的内容不同于post_item_card_layout
  • @DrMido 我不会说这是不可能的。我刚刚说过 viewType 是用于适配器的。所以经验法则:1)您想要不同的单元格 UI:然后创建不同的视图类型,2)您想要不同的单元格布局(列表或网格):然后只需更改布局管理器。 @Sam 的答案。 isViewWithCatalog 提到的仅在与布局管理器存在 1 1 关系时才有效,因为它们不会使用彼此的缓存。但一般来说,这不是推荐的方法。

标签: android android-layout android-recyclerview android-viewholder recyclerview-layout


【解决方案1】:

为防止滚动时混合布局,您应该使用 ViewFlipper 和三个不同的 RecyclerView's ,这意味着每个布局都有 RecyclerView。

第 1 步:

  • 为三个布局创建一个公共枚举
public enum ViewType {
    CARD_LIST_LAYOUT, TITLE_LAYOUT, CARD_MAGAZINE_LAYOUT;
}
  • 在 PostAdapter 中创建一个 ViewType 变量并将其传递给构造函数,并通过 onCreateViewHolder 上的 if & else 检查以了解选择了哪个布局
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);
        }
    }

第 2 步:

  • 在包含主RecyclerView的类中创建一个ViewFlipper,带有三个child的Layout和RecyclerView
<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>
  • MainActivity 中像这样定义变量
         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);
  • 为每个 RecyclerView 添加ScrollListener
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) {

                }

            }  
        });

第 3 步:

  • 最后在onOptionsItemSelected点击时切换三种布局
@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;
        }

[重要提示] 对于每个布局或 RecyclerView,您应该对旧的主 RecyclerView 执行 3 次,就像上面的 ScrollListener 示例一样。

希望这与您合作,如果您有任何疑问,请告诉我

【讨论】:

  • 这应该可以,但我看不到您在更改回收站视图之前和之后的当前滚动位置。此外,我认为您可以仅使用一个 Recycler 视图来实现此目的,我会尝试并发布我的结果。
  • 对不起,我无法在那里发表评论,因为我的声誉昨天被扣除到 50 以下,但是,我看到其他 question 关于这个问题,我试图用一个 RecyclerView 来解决这个问题,如一些答案中所述但这会导致滚动时混合布局,并使视图看起来很难看,使用具有三个布局的 ViewFlipper 没有问题,每个布局与 RecylerView。这不会导致任何过载或挂起应用程序。我认为它就是为此目的而设计的。
【解决方案2】:

不需要为此使用多个Recyclerview

您可以使用单个 RecyclerviewMultiple viewType 来实现此目的

当您想更改 Recyclerview 的布局时,只需更改 RecyclerviewLayoutManagerviewType 即可

示例代码

试试这个方法

首先为您的多视图类型创建三个布局

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>

数据适配器

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);
        }
    }
}

主活动

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 布局

<?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>

输出

https://youtu.be/L3slKTy2bzI

【讨论】:

  • 感谢您的回答,我复制了您的所有代码,当我尝试更改布局时得到了java.lang.ClassCastException: abtallaldigital.blogspot.com.dummyapp.PostAdapter$TitleListViewHolder cannot be cast to abtallaldigital.blogspot.com.dummyapp.PostAdapter$GridViewHolder
  • @DrMido 你需要创建 3 个不同的 RecyclerView.ViewHolder 就像在我的 DataAdapter 类中再次检查它
  • @DrMido 请与问题分享您的适配器类,让我检查您的代码
  • @DrMido 还根据VIEW_TYPE 内部onCreateViewHolder() 方法确保您返回正确的ViewHolder
  • @DrMido 我无法使用您的代码为我重现您的问题,它正在工作,您可以请与 github repo 相同的代码
【解决方案3】:

您可以通过在适配器中实现 VIEW_TYPE 来简单地实现这一点。 RecyclerView Adapterpublic int getViewType(int position)中有一个重写的方法,一般用于将各种类型的视图混合到一个RecyclerView中。

但你也可以在你的情况下使用它。首先定义您的视图类型的枚举。然后在您的适配器内部维护一个变量来存储当前的 viewType,从警报对话框项单击相应地更新该变量。

在您的onCreateViewHolderonBindViewHolder 方法中使用当前的viewType 值来确定您当前应该使用哪个布局以及现在需要更新哪些UI 元素。还可以从单击时的警报对话框项更新 RecyclerView 布局管理器。

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 {

        }
    }
}

更新:每次调用updateViewType 方法时,还需要像这样调用notifyDataSetChanged 方法:

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

*** 我已经在我的设备上测试了这段代码,它按预期工作。请注意,在扩展布局和使用 TextView 和 ImageView 等布局元素时,应小心处理 VIEW_TYPE。在我之前的回答中,我将视图类型与错误的布局混合在一起,这可能是您看到混合布局作为输出的唯一原因。

*** 此外,getItemViewType 方法被错误地重命名为 getViewType,这是我的代码中导致混合输出的另一个罪魁祸首。

【讨论】:

  • 嗨 sourav.bh,感谢您的回答,但不幸的是,当我滚动时使用这种方式会导致布局之间混合我看到一些项目是旧布局,​​我试图调用 adapter.notifyDataSetChanged(); 但也没有t 影响
  • 对不起,我错过了每次你调用updateViewType方法时,你还应该调用notifyDataSetChanged。我在我的回答中发现了一个缺陷,你应该比较你在适配器方法中找到的 viewType。我正在与currentViewType 变量进行比较,这是不正确的。请查看我编辑的答案。
  • @DrMido 您是否尝试过更新的答案?还是还是不行?
  • @sourav.bh 你的答案看起来是对的,但如果你只使用一个,我会避免在 onCreateViewHolder 中夸大所有 3 个布局。当您已经检查过类型时,最好为所需的充气。另外,在第二种情况下,您似乎仍在与currentViewType 比较VIEW_TYPE_GRID
  • 是的,您不需要在此处扩充所有三个布局。我刚刚使用了您提到的代码,并希望首先让您对逻辑感到满意。我为重构问题道歉,我昨天从移动网络编辑,这很不稳定。无论如何,我现在正在审查代码并将相应地更新。如果它对您有用,请考虑将其标记为已接受,以便其他人也能从中受益。
【解决方案4】:

不要再做。只需单击 alertdialog 更改 recyclerview 的布局。如果你想使用网格布局而不是改为网格布局,LinearLayout 并设置adapter.notifydatasetchanged,而如果你想改变recyclerview 的Adapter 行的布局而不是在recyclerview 的adapter 中添加一个参数化的构造函数。之后读取参数并据此设置视图。像这样

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

在 oncreateviewholder 中放这个

 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;
    }

在那之后 notifydataset 改变了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-28
    • 1970-01-01
    • 1970-01-01
    • 2020-11-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多