我有一个父级布局,其中有一些TextViews和RecyclerView。还有 child 布局,其中有一个RecyclerView,适配器有5种不同的视图类型
对于子 recyclerview,我使用的适配器具有5种不同的布局,其中包括
当子 RecyclerView中包含超过 x 个项目时,就会发生此问题。当我向下滚动到屏幕底部,然后向上滚动到屏幕顶部并再次向下滚动到屏幕底部时,子 RecyclerView 会显示错误的布局/查看类型。
parent_layout.xml
<layout 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">
<data>
<import type="android.view.View" />
<variable
name="viewModel"
type="home.HomeTabViewModel" />
</data>
<android.support.constraint.ConstraintLayout
android:id="@+id/cl_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="@+id/v_toolbar"
layout="@layout/toolbar_home_v3" />
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_home_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:clipToPadding="false"
android:overScrollMode="never"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/v_toolbar" />
</android.support.constraint.ConstraintLayout>
</layout>
child_layout.xml
<layout 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.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dimens_32dp">
<TextView
android:id="@+id/tv_title"
style="@style/TextSoftBlackBold.20sp"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dimens_16dp"
android:layout_marginRight="@dimen/dimens_16dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
tools:text="Popular Ideas" />
<TextView
android:id="@+id/tv_subtitle"
style="@style/TextDarkGrayNormal.14sp"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dimens_16dp"
android:layout_marginTop="@dimen/dimens_7dp"
android:layout_marginRight="@dimen/dimens_16dp"
android:ellipsize="end"
android:maxLines="2"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_title"
tools:text="Popular events happening during your stay in Bali" />
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_menu_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dimens_2dp"
app:layout_constraintTop_toBottomOf="@+id/tv_subtitle" />
</android.support.constraint.ConstraintLayout>
</layout>
BaseMenuAdapter.kt
class BaseMenuAdapter(val context: Context?,
private var contents: List<HomeViewParam.Content>?,
private val menuGrid: HomeItem.MenuGrid?) :
RecyclerView.Adapter<BaseMenuAdapter.MyViewHolder>() {
companion object {
const val VIEW_TYPE_LANDSCAPE = 0
const val VIEW_TYPE_LANDSCAPE_CARD = 1
const val VIEW_TYPE_PORTRAIT = 2
const val VIEW_TYPE_TWO_COLUMN = 3
const val VIEW_TYPE_SQUARE = 4
}
inner class MyViewHolder : RecyclerView.ViewHolder {
var landscapeBinding: ViewTemplateLandscapeBinding? = null
var landscapeCardBinding: ViewTemplateLandscapeCardBinding? = null
var portraitBinding: ItemHomeMenuPortraitBinding? = null
var twoColumnBinding: ItemHomeMenuTwoColumnBinding? = null
var squareBinding: ItemHomeMenuSquareBinding? = null
constructor(binding: ViewTemplateLandscapeBinding) : super(binding.root) {
landscapeBinding = binding
}
constructor(binding: ViewTemplateLandscapeCardBinding) : super(binding.root) {
landscapeCardBinding = binding
}
constructor(binding: ItemHomeMenuPortraitBinding) : super(binding.root) {
portraitBinding = binding
}
constructor(binding: ItemHomeMenuTwoColumnBinding) : super(binding.root) {
twoColumnBinding = binding
}
constructor(binding: ItemHomeMenuSquareBinding) : super(binding.root) {
squareBinding = binding
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseMenuAdapter.MyViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding: ViewDataBinding
return when (viewType) {
0 -> {
binding = DataBindingUtil.inflate(inflater, R.layout.view_template_landscape, parent, false)
MyViewHolder(binding as ViewTemplateLandscapeBinding)
}
1 -> {
binding = DataBindingUtil.inflate(inflater, R.layout.view_template_landscape_card, parent, false)
MyViewHolder(binding as ViewTemplateLandscapeCardBinding)
}
2 -> {
binding = DataBindingUtil.inflate(inflater, R.layout.item_home_menu_portrait, parent, false)
MyViewHolder(binding as ItemHomeMenuPortraitBinding)
}
3 -> {
binding = DataBindingUtil.inflate(inflater, R.layout.item_home_menu_two_column, parent, false)
MyViewHolder(binding as ItemHomeMenuTwoColumnBinding)
}
4 -> {
binding = DataBindingUtil.inflate(inflater, R.layout.item_home_menu_square, parent, false)
MyViewHolder(binding as ItemHomeMenuSquareBinding)
}
else -> {
throw RuntimeException("The type has to be ONE or TWO")
}
}
}
override fun onBindViewHolder(holder: BaseMenuAdapter.MyViewHolder, position: Int) {
context?.resources.run {
when (holder.itemViewType) {
VIEW_TYPE_LANDSCAPE -> {
val binding = holder.landscapeBinding
binding?.run {
val item = contents?.let { it[holder.adapterPosition] }
binding.content = item
root.setOnClickListener { AllWebViewActivityV2.startThisActivity(context, item?.title ?: "",
item?.url ?: "") }
executePendingBindings()
}
}
VIEW_TYPE_LANDSCAPE_CARD -> {
val binding = holder.landscapeCardBinding
binding?.run {
val item = contents?.let { it[holder.adapterPosition] }
binding.content = item
root.setOnClickListener { AllWebViewActivityV2.startThisActivity(context, item?.title ?: "",
item?.url ?: "") }
executePendingBindings()
}
}
VIEW_TYPE_TWO_COLUMN -> {
val binding = holder.twoColumnBinding
binding?.run {
val item = contents?.let { it[holder.adapterPosition] }
binding.content = item
root.setOnClickListener { AllWebViewActivityV2.startThisActivity(context, item?.title ?: "",
item?.url ?: "") }
executePendingBindings()
}
}
VIEW_TYPE_PORTRAIT -> {
val binding = holder.portraitBinding
binding?.run {
val item = contents?.let { it[holder.adapterPosition] }
binding.content = item
root.setOnClickListener { AllWebViewActivityV2.startThisActivity(context, item?.title ?: "",
item?.url ?: "") }
executePendingBindings()
}
}
VIEW_TYPE_SQUARE -> {
val binding = holder.squareBinding
binding?.run {
val item = contents?.let { it[holder.adapterPosition] }
binding.content = item
root.setOnClickListener { AllWebViewActivityV2.startThisActivity(context, item?.title ?: "",
item?.url ?: "") }
executePendingBindings()
}
}
else -> {}
}
}
}
override fun getItemViewType(position: Int): Int {
contents?.let {
return when (menuGrid?.templateType) {
TemplateType.LANDSCAPE -> VIEW_TYPE_LANDSCAPE
TemplateType.LANDSCAPE_CARD -> VIEW_TYPE_LANDSCAPE_CARD
TemplateType.TWO_COLUMN -> VIEW_TYPE_TWO_COLUMN
TemplateType.POTRAIT -> VIEW_TYPE_PORTRAIT
TemplateType.SQUARE -> VIEW_TYPE_SQUARE
else -> -1
}
}
return -1
}
override fun getItemCount(): Int {
return contents?.size ?: 0
}
override fun setHasStableIds(hasStableIds: Boolean) {
super.setHasStableIds(false)
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
fun setItems(contents: List<HomeViewParam.Content>?) {
this.contents = contents
}
}
因此,如上所述,当我向上或向下滚动时,某些项目有时会使用错误的视图类型
答案 0 :(得分:2)
您需要为每种布局类型定义一个ViewHolder,然后分别使用 getItemViewType()和 onBindViewHolder(),大致如下:
@Override
public int getItemViewType(int position) {
if (isValidPosition(position)) {
Data d = mDataset[position];
if (d instanceof LandscapeData) {
return VIEW_TYPE_LANDSCAPE;
} else if (d instanceof PortraitData) {
return VIEW_TYPE_PORTRAIT;
}
// more else-ifs here
}
// default to landscape
return VIEW_TYPE_LANDSCAPE;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Data d = mDataset[position];
if (holder instanceof LandscapeVH) {
// binding of dataset for landscape layouts
LandscapeData data = (LandscapeData) d;
LandscapeVH vh = (LandscapeVH) holder;
// bind the data to the view on the fly here
vh.myTextView.setText(data.getLandscapeTitle());
} else if (holder instanceof PortraitVH) {
// binding of dataset for portrait layouts
PortraitData data = (PortraitData) d;
PortraitVH vh = (PortraitVH) holder;
// bind the data to the view on the fly here
vh.myTextView.setText(data.getPortraitTitle());
}
// more else-ifs here
}
注意:您的mDataset []是唯一的事实来源,它包含数据类型的数据集,这些数据集可以子类化为更专业的数据集,例如LandscapeData和PortraitData,它们与布局的类型紧密相关。