【问题标题】:Force RecyclerView to call onCreateViewHolder强制 RecyclerView 调用 onCreateViewHolder
【发布时间】:2015-10-26 07:38:01
【问题描述】:

我有一个RecyclerView,可以将项目显示为列表、小网格或大网格,并且可以在运行时更改。根据用户选择的样式,我会在onCreateViewHolder 中添加不同的布局。

我还使用layoutManger.setSpanSizeLookUp() 在样式之间切换。我的代码是这样的

layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
        @Override
        public int getSpanSize(int position) {
            if(showType == ProductAdapter.SHOW_TYPE_SMALL_GRID)
                return 1;
            else
                return columnCount; //show one item per row
        }
    });

@Override
public void onClick(View v) {
    if(showType == ProductAdapter.SHOW_TYPE_SMALL_GRID)
        showType = ProductAdapter.SHOW_TYPE_LARGE_GRID;
    else
        showType = ProductAdapter.SHOW_TYPE_SMALL_GRID;


    int firstVisibleItem = layoutManager.findFirstVisibleItemPosition();
    adapter = new ProductAdapter(getActivity(), productList, showType);
    recyclerView.setAdapter(adapter);
    layoutManager.scrollToPosition(firstVisibleItem);
}

问题是强制调用onCreateViewHolder 每次用户更改样式时我都会创建一个新对象。有没有别的办法?!强制召回onBindViewHolder()。我只是使用adapter.notifyDataSetChanged() 我怎样才能得到与onCreateViewHolder? 类似的东西

任何不使用多个适配器的解决方案都足够好!

【问题讨论】:

  • 您说“不使用多个适配器”很好。更换适配器不是一个好的解决方案。

标签: android android-adapter android-recyclerview


【解决方案1】:

你需要做的是:

  1. 修改你的Adapter:

  • 指定您的Adapter 可以膨胀的两种Views

private static final int LARGE_GRID_ITEM = -1;
private static final int SMALL_GRID_ITEM = -2;
  • 创建一个可以存储当前类型的字段mCurrentType

  • 使用您的Adapter's getItemViewType。比如像这样:

@Override
public int getItemViewType (int position) {
    return mCurrentType;
}
  • 在您的createViewHolder 中使用viewType 来决定您需要创建什么类型的ViewHolder

public final RecyclerView.ViewHolder createViewHolder (ViewGroup parent, int viewType){
    if (viewType == LARGE_GRID_ITEM) {
        //return large grid view holder
    } else {
        //return small grid view holder
    }
}
  • 此外,您还可以创建方法:

public void toggleItemViewType () {
    if (mCurrentType == LARGE_GRID_ITEM){
        mCurrentType = SMALL_GRID_ITEM;
    } else {
        mCurrentType = LARGE_GRID_ITEM;
    }
}

public boolean displaysLargeGrid(){
    return mCurrentType == LARGE_GRID_ITEM;
}
  1. 修改您发布的代码:

layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
        @Override
        public int getSpanSize(int position) {
            if (adapter.displaysLargeGrid()) {
                return 1;
            } else {
                return columnCount; //show one item per row
            }
        }
    });

@Override
public void onClick(View v) {
    adapter.toggleItemViewType();
    adapter.notifyDataSetChanged();
}

【讨论】:

  • 我想你没有明白我的问题。您的代码很好,但是当您调用切换 mCurrentType 更改但不会调用 createViewHolder 时! notifyDataSetChanged() 仅强制调用 onBindView 而不是 onCreateViewHolder()。所以问题仍然存在,如何强制调用 onCreateViewHolder() 以使正确的项目膨胀?
  • 我确实得到了你的问题。你没有得到我的回答。它会解决您的问题并为您提供正确的方法。你有没有试过我的代码?如果没有大网格的持有者,它将调用onCreateViewHolder。我的代码改变了getItemViewType 返回的内容。当您调用 notifyDataSetChanged 时,适配器将检查 itemViewTypes 的位置并决定是否需要调用 onCreateViewHolder (如果这种类型的视图没有可用的持有人)或只是 onBindViewHolder (如果它已经有一些持有人离开) .您需要有两种类型的持有人。
  • 他的代码可以工作,因为他已经通过调用 notifyDataSetChanged() 清除了整个列表,这对性能不利,而您应该调用 notifyItemChanged()。调用 notifyDataSetChanged() 就像重新创建列表一样。对于一个小列表,您可以这样做,但对于大量项目或单行布局,您不应该这样做。
  • 这不是答案!你完全改变了标题
  • @mahdiazarm SO 问题不仅仅是一个标题。它也有描述。这是问题中提出的问题的正确答案。
【解决方案2】:

这不是最佳选择,但最好创建一个新的Adapter,它将调用onCreateViewHolder()。通过这种方式,您可以避免麻烦,但代价是非常小的性能问题。

【讨论】:

    猜你喜欢
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    • 2021-08-07
    • 1970-01-01
    • 2021-11-19
    • 2017-07-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多