我有一个非常复杂的RecyclerView
,由多个viewType组成。其中之一是ViewType.UNITS
(我制作的代表每个viewType的枚举)。 UNITS
具有需要显示的21个不同视图的数据。
当我向下滚动到recyclerView的底部时,一切都很好。当我向上滚动时,带有ViewType.UNITS
的第一个视图(也许在整个position == 10
中为recyclerView
)被复制并显示在第三个ViewType.UNITS
视图的位置。
所以这里向下滚动时是正确的:
UNIT1
UNIT2
UNIT3
UNIT4
UNIT5
...etc
但是当我向上滚动时,有时会看到以下内容:
UNIT1
UNIT2
UNIT1 //<-- problem here
UNIT4
UNIT5
...etc
viewHolder
实例显示错误的数据。知道如何发生吗?完整代码:
/**
* An adapter for the recyclerView in the {@link HomeView}
*/
public class HomeRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
final String unitTitle;
final Resources res;
final SparseArray<ViewType> viewTypeCache;
final SparseArray<MainArticleCategoryViewModel> mainArticleCategoryViewModelMap;
public HomeRecyclerAdapter(Resources res) {
this.res = res;
unitTitle = res.getString(R.string.units_section_title);
mainArticleCategoryViewModelMap = new SparseArray<>(GenericArticleCategory.MAIN.length);
viewTypeCache = new SparseArray<>(getItemCount());
}
public static HomeRecyclerAdapter newInstance(Resources res) {
return new HomeRecyclerAdapter(res);
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final View v;
switch (ViewType.getViewTypeFromInt(viewType)) {
case PADDING_TOP:
v = PADDING_TOP.inflateLayout(parent);
return HeaderRecyclerViewHolder.newInstance(v);
case HOME_BUCKET:
v = HOME_BUCKET.inflateLayout(parent);
return HomeBucketRecyclerViewHolder.newInstance(v);
case UNITS_TITLE:
v = UNITS_TITLE.inflateLayout(parent);
return HomeTitleRecyclerViewHolder.newInstance(v);
case UNITS:
v = UNITS.inflateLayout(parent);
return new HomeUnitsRecyclerViewHolder(v);
case LINK_BUTTON:
v = LINK_BUTTON.inflateLayout(parent);
return HomeLinkRecyclerViewHolder.newInstance(v);
default:
throw new RuntimeException();
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
switch (ViewType.getViewTypeFromInt(getItemViewType(position))) {
case HOME_BUCKET:
HomeBucketRecyclerViewHolder homeBucketRecyclerViewHolder = (HomeBucketRecyclerViewHolder) viewHolder;
final GenericArticleCategory articleCategory = GenericArticleCategory.MAIN[position - HOME_BUCKET.getStart()];
homeBucketRecyclerViewHolder.setArticleCategory(articleCategory);
final MainArticleCategoryViewModel mainArticleCategoryViewModel = mainArticleCategoryViewModelMap.get(articleCategory.getId());
if (mainArticleCategoryViewModel != null)
homeBucketRecyclerViewHolder.setImage(mainArticleCategoryViewModelMap.get(articleCategory.getId()).getFirstImageUrl());
break;
case UNITS_TITLE:
((HomeTitleRecyclerViewHolder) viewHolder).setText(unitTitle);
break;
case UNITS:
final HomeUnitsRecyclerViewHolder homeUnitsRecyclerViewHolder = (HomeUnitsRecyclerViewHolder) viewHolder;
homeUnitsRecyclerViewHolder.bind(GenericArticleCategory.UNITS[position - UNITS.getStart()]);
break;
case LINK_BUTTON:
//all data needed for this is set via .xml, so no need to bind.
break;
}
}
@Override
public int getItemViewType(int position) {
ViewType viewType = viewTypeCache.get(position);
if (viewType != null)
return viewType.getItemViewType();
if (isViewType(PADDING_TOP, position)) {
viewType = PADDING_TOP;
} else if (isViewType(HOME_BUCKET, position)) {
viewType = HOME_BUCKET;
} else if (isViewType(UNITS_TITLE, position)) {
viewType = UNITS_TITLE;
} else if (isViewType(UNITS, position)) {
viewType = UNITS;
} else if (isViewType(LINK_BUTTON, position)) {
viewType = LINK_BUTTON;
}
if (viewType != null) {
viewTypeCache.put(position, viewType);
return viewType.getItemViewType();
}
throw new RuntimeException("There is no position that matches the position " + position);
}
@Override
public int getItemCount() {
int sum = 0;
for (ViewType viewType : ViewType.values()) {
sum += viewType.getItemCount();
}
return sum;
}
public boolean isViewType(ViewType viewType, int position) {
if (viewType.getStart() <= position && position <= viewType.getEnd())
return true;
else
return false;
}
public void addImage(MainArticleCategoryViewModel viewModel) {
final int id = viewModel.getId();
mainArticleCategoryViewModelMap.put(id, viewModel);
notifyItemChanged(id);
}
public enum ViewType implements ViewTypeItem {
HOME_BUCKET(0, R.layout.home_recycler_item_category) {
@Override
public int getStart() {
return PADDING_TOP.getStart() + 1;
}
@Override
public int getItemCount() {
return GenericArticleCategory.MAIN.length;
}
},
UNITS_TITLE(1, R.layout.home_recycler_item_title) {
@Override
public int getStart() {
return HOME_BUCKET.getEnd() + 1;
}
@Override
public int getItemCount() {
return 1;
}
},
UNITS(2, R.layout.home_recycler_item_units) {
@Override
public int getStart() {
return UNITS_TITLE.getEnd() + 1;
}
@Override
public int getItemCount() {
return GenericArticleCategory.UNITS.length;
}
},
LINK_BUTTON(4, R.layout.home_recycler_item_external_link_group) {
@Override
public int getStart() {
return UNITS.getEnd() + 1;
}
@Override
public int getItemCount() {
return 1;
}
},
PADDING_TOP(10, R.layout.seabee_resources_recycler_item_padding_top) {
@Override
public int getStart() {
return 0;
}
@Override
public int getItemCount() {
return 1;
}
};
private final int itemViewType;
@LayoutRes
private final int layoutResId;
ViewType(int itemViewType, @LayoutRes int layoutResId) {
this.itemViewType = itemViewType;
this.layoutResId = layoutResId;
}
public static ViewType getViewTypeFromInt(int itemViewType) {
for (ViewType viewType : ViewType.values()) {
if (viewType.getItemViewType() == itemViewType)
return viewType;
}
throw new RuntimeException("There is no type that matches the itemViewType " + itemViewType + " + make sure your using types correctly");
}
public int getItemViewType() {
return itemViewType;
}
@Override
public int getEnd() {
return getStart() + getItemCount() - 1;
}
private View inflateLayout(ViewGroup parent) {
return LayoutInflater.from(parent.getContext()).inflate(layoutResId, parent, false);
}
public int getSpanSize(int homeGridTotalSpan, Resources res) {
switch (this) {
case PADDING_TOP:
return homeGridTotalSpan;
case HOME_BUCKET:
return homeGridTotalSpan / res.getInteger(R.integer.home_bucket_span);
case UNITS_TITLE:
return homeGridTotalSpan / res.getInteger(R.integer.home_title_span);
case UNITS:
return homeGridTotalSpan / res.getInteger(R.integer.home_units_span);
case LINK_BUTTON:
return homeGridTotalSpan / res.getInteger(R.integer.home_link_span);
default:
throw new RuntimeException("Missing an enum in this switch statement");
}
}
}
interface ViewTypeItem {
int getStart();
int getEnd();
int getItemCount();
}
}
最佳答案
在onCreateViewHolder()
中,您不应再调用getViewTypeFromInt
。 onCreateViewHolder()
的第二个参数,即int itemViewType
应该已经使用。
因此,只需更新您的onCreateViewHolder
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final View v;
switch (viewType) {
case PADDING_TOP:
v = PADDING_TOP.inflateLayout(parent);
return HeaderRecyclerViewHolder.newInstance(v);
case HOME_BUCKET:
v = HOME_BUCKET.inflateLayout(parent);
return HomeBucketRecyclerViewHolder.newInstance(v);
case UNITS_TITLE:
v = UNITS_TITLE.inflateLayout(parent);
return HomeTitleRecyclerViewHolder.newInstance(v);
case UNITS:
v = UNITS.inflateLayout(parent);
return new HomeUnitsRecyclerViewHolder(v);
case LINK_BUTTON:
v = LINK_BUTTON.inflateLayout(parent);
return HomeLinkRecyclerViewHolder.newInstance(v);
default:
throw new RuntimeException();
}
}