问题摘要
我在活动中有一个RecyclerView列表,其中有一个actionBar按钮,用于在LIST和GRID布局之间切换RecyclerView。
将列表视为LIST和GRID时,项目的布局会有所不同。
查看LIST中的项目时,行格式为
|----|
|icon| Item Name
|----|
在GRID中查看项目时,行格式为
|--------------|
| large icon |
| |
| |
| |
|--------------|
Item Name
因此,我在列表中查看我的列表
|----|
|icon| Item1
|----|
|----|
|icon| Item2
|----|
|----|
|icon| Item3
|----|
|----|
|icon| Item3
|----|
当我将列表视为GRID时,我看到了
|--------------| |--------------|
| large icon | | large icon |
| | | |
| | | |
| | | |
|--------------| |--------------|
Item1 Item2
|--------------| |--------------|
| large icon | | large icon |
| | | |
| | | |
| | | |
|--------------| |--------------|
Item3 Item4
当我使用actionBar按钮将列表视图从LIST切换到GRID或GRID切换到LIST时,某些视图仍会在其他样式的布局中呈现。我相信,在切换之前滚动视线的视图会被回收再利用而不是重新创建。
例如,如果我从GRID转到LIST,我会看到
|--------------|
| large icon |
|----| | |
|icon| Item1 | |
|----| | |
|--------------|
Item2
|--------------| |--------------|
| large icon | | large icon |
| | | |
| | | |
| | | |
|--------------| |--------------|
Item3 Item4
背景代码信息
我有2个布局管理器;每个布局样式一个
private RecyclerView.LayoutManager linearLayoutManager;
private RecyclerView.LayoutManager gridLayoutManager;
在适配器中我存储我是否将列表显示为网格或列表
enum ListViewEnum{
LIST,
GRID
}
ListViewEnum listViewStyle = ListViewEnum.LIST;
public ListViewEnum getListStyle() {
return listViewStyle;
}
列表中项目的布局取决于列表是作为列表还是网格呈现。
ViewHolderList
ViewHolderGrid
创建视图持有者时,我将视图持有者的类型基于适配器列表视图样式
protected RecyclerView.ViewHolder getItemViewHolder(ViewGroup parent){
if (listViewStyle == ListViewEnum.LIST){
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_row, parent, false);
return new ViewHolderList(itemView, ....);
} else {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.grid_row, parent, false);
return new ViewHolderGrid(itemView, ....);
}
}
当用户点击actionBar按钮时,我切换适配器的值
getListAdapter().setListViewMode(ListViewMode.LIST);
然后刷新
listView.setLayoutManager(getListAdapter().getListStyle() == ListViewEnum.LIST ? linearLayoutManager : gridLayoutManager);
getListAdapter().notifyDataSetChanged();
listView.invalidateItemDecorations();
invalidateOptionsMenu();
我知道我正在刷新列表适配器,但它不会放弃recycleViews。调试显示,在点击切换按钮时,我看到只有" onBindViewHolder"对于某些职位(回收的职位)和" onCreateViewHolder"和" onBindViewHolder"(对于新的)因此表明旧的视图持有者正在被回收。
如何刷新列表以便不会从错误的列表样式重新使用ViewHolders?
答案 0 :(得分:2)
来自@Abbas的评论是正确的,getItemViewType()可能是你最好的选择。根据您的数据,您可以使用一个持有者,但如果数据项不同,您可能必须创建两个。使用适配器内的getItemViewType()调用来确定要显示的内容。您将需要将标志从活动或回调传递到适配器中以获取类型。
public static final int SMALL_VIEW = 0;
public static final int LARGE_VIEW = 1;
private int mType = 0;
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v;
RecyclerView.ViewHolder viewHolder = null;
// Create the Holders depending on the type, the view type
// will come from the getItemViewType() call.
switch ( viewType ) {
case SMALL_VIEW:
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_row, parent, false);
viewHolder = new ViewHolderList(mContext, v);
break;
case LARGE_VIEW:
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.grid_row, parent, false);
viewHolder = new ViewHolderGrid(mContext, v);
default:
}
return viewHolder;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
// This switch may not be necessary if you are using
// the same holder for both items.
switch ( getItemViewType(position) ) {
case SMALL_ITEM:
ViewHolderList list = (ViewHolderList)holder;
list.setData(mData.get(position));
break;
case LARGE_ITEM:
ViewHolderGrid grid = (ViewHolderGrid)holder;
grid.setData(mData.get(position));
}
}
@Override
public int getItemViewType(int position) {
// Normally you identify the data type at position and
// switch the view, for your application you can switch
// for all.
return mType;
}
public void setViewType(int type) {
mType = type;
}
答案 1 :(得分:1)
由于RecyclerViews内存管理,RecyclerView尝试重用视图以更快地滚动。我认为使用两个适配器实例而不是一个,并使用选定的适配器重新填充回收器可能有所帮助。