我已经能够创建一个可以托管两个不同ViewHolder的RecyclerView,具体取决于我模型中的数据。然而,我仍然对RecyclerView和相应的适配器如何使其工作感到困惑。
我的理由如下:当只使用一个viewType时,RecyclerView使用Adapters onCreateViewHolder 方法创建填充一个屏幕所需的ViewHolders。此数量可能小于所需的总行数。 创建每个ViewHolder后,它要求Adapter使用 onBindViewHolder 将模型数据绑定到ViewHolder 在滚动列表时,RecyclerView始终重用相同的ViewHolders,但使用之前的 onBindViewHolder 方法将不同的数据绑定到它们。它可以毫无问题地执行此操作,因为model和viewType之间存在1-1关系。
但是当有多个viewTypes时,我感到困惑。 在我的用例中,两种视图类型之间只有很小的差异。类型A只有两个TextView,类型B有两个textViews 和一个Button。我创建了一个Abstract SimpleHolder ViewHolder类,它有两个TextView。对于类型A,除了调用超类构造函数之外,具体类不会做太多事情。对于类型B,我还扩展了该抽象超类,并为Button提供了额外的属性。
在我的列表中说出前10个项目中的5个是A类型,5个是B类型(随机放置)。 RecyclerView必须创建ViewHolders,并且看到它必须为类型A创建5个ViewHolders,为类型B创建5个。它知道在使用哪个时因为我实现了 getItemViewType 方法并使用了 onCreateViewHolder 中的viewType参数。 我猜在内部看起来像这样:
这里的数字是屏幕上的位置。当用户没有滚动时,一切都很好。但是一旦他/她做了,事情就会开始发生变化。我的屏幕上的位置3可能不再存在类型B,但现在是类型A.但是位置3是"保留"对于B型! RecyclerView如何处理此问题?
我可以想到以下选项,但我不确定。
这是两个中的一个吗?或者是其他东西?对于文本墙感到抱歉,但我想完全解释我的推理。
必要时编码:
private abstract class CrimeHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private TextView mTitleTextView;
private TextView mDateTextView;
private Crime mCrime;
private CrimeHolder(LayoutInflater inflater, ViewGroup parent, int viewType) {
super(inflater.inflate(viewType, parent, false));
itemView.setOnClickListener(this);
mTitleTextView = (TextView) itemView.findViewById(R.id.crime_title);
mDateTextView = (TextView) itemView.findViewById(R.id.crime_date);
}
public void bind(Crime crime) {
Log.d("CrimeHolder", "bind");
this.mCrime = crime;
mTitleTextView.setText(mCrime.getTitle());
mDateTextView.setText(mCrime.getDate().toString());
}
@Override
public void onClick(View view) {
Toast.makeText(getActivity(), mCrime.getTitle() + " clicked", Toast.LENGTH_SHORT).show();
}
}
private class SimpleCrimeHolder extends CrimeHolder {
private SimpleCrimeHolder(LayoutInflater inflater, ViewGroup parent, int viewType) {
super(inflater, parent, viewType);
Log.d("SimpleCrimeHolder", "Constructor");
}
}
private class SeriousCrimeHolder extends CrimeHolder {
private Button mContactPoliceButton;
private SeriousCrimeHolder(LayoutInflater inflater, ViewGroup parent, int viewType) {
super(inflater, parent, viewType);
Log.d("SeriousCrimeHolder", "Constructor");
mContactPoliceButton = (Button) itemView.findViewById(R.id.contact_police_button);
mContactPoliceButton.setOnClickListener(view ->
Toast.makeText(getActivity(), "Contacting Police!", Toast.LENGTH_SHORT).show());
}
}
private class CrimeAdapter extends RecyclerView.Adapter<CrimeHolder> {
private List<Crime> mCrimes;
private CrimeAdapter(List<Crime> crimes) {
this.mCrimes = crimes;
}
@Override
public CrimeHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
if (viewType == R.layout.list_item_crime) {
Log.d("Adapter", "onCreateViewHolder - SimpleCrimeHolder");
return new SimpleCrimeHolder(layoutInflater, parent, viewType);
} else {
Log.d("Adapter", "onCreateViewHolder - SeriousCrimeHolder");
return new SeriousCrimeHolder(layoutInflater, parent, viewType);
}
}
@Override
public void onBindViewHolder(CrimeHolder holder, int position) {
Log.d("Adapter", "onBindViewHolder - positie " + position);
Crime crime = mCrimes.get(position);
holder.bind(crime);
}
@Override
public int getItemViewType(int position) {
Log.d("Adapter", "getItemViewType pos " + position + " - crime is srs: " + mCrimes.get(position).requiresPolice());
if (mCrimes.get(position).requiresPolice()) {
return R.layout.list_item_serious_crime;
} else {
return R.layout.list_item_crime;
}
}
@Override
public int getItemCount() {
return mCrimes.size();
}
}
}