在 onCreateViewHolder 中创建的 ViewHolder 中手动创建的视图
Manually created view in ViewHolder created in onCreateViewHolder
我想制作通用适配器,让我重新使用它。这就是为什么我决定不通过 inflating
创建视图,而是将自定义的、以前创建的视图传递给 ListAdapter
中的 ViewHolder
(RecyclerView
) in onCreateViewHolder
。根据其文档,它应该是可能的,因为它说:
You can either create a new View manually or inflate it from an XML layout file.
这是我的适配器实现:
class BaseAdapter<T, V : View>(
private val adapterConfig: AdapterConfig<T, V>,
private val onClick: (T) -> (Unit)
) : ListAdapter<T, BaseViewHolder<V>>(adapterConfig.diffCallback) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<V> {
return adapterConfig.viewHolder.apply {
itemView.setOnClickListener { onClick(getItem(adapterPosition)) }
}
}
override fun onBindViewHolder(holder: BaseViewHolder<V>, position: Int) {
adapterConfig.bind(getItem(position), holder, position)
}
}
AdapterConfig
实现 class 负责创建 ViewHolder
,它看起来像这样:
override val viewHolder: BaseViewHolder<ScorerView> = BaseViewHolder(ScorerView(context))
BaseViewHolder
class:
class BaseViewHolder<out V : View>(val v: V) : RecyclerView.ViewHolder(v)
(到现在为止没什么有趣的)
我的ScorerView
是:
class ScorerView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
init {
LayoutInflater.from(context).inflate(R.layout.item_ranking, this, false)
}
fun configure(id: String, player: String, team: String, matchSet: String, points: String, pointsAvg: String) {
idTextView.text = id
playerTextView.text = player
teamTextView.text = team
matchSetTextView.text = matchSet
pointsTextView.text = points
pointsAvgTextView.text = pointsAvg
}
}
问题是,当我将 false
传递给 inflate
函数时(没关系,因为 RecyclerView
要求项目视图未附加到根视图)然后我的小部件实例(例如 idTextView
)为空。否则,当我通过传递 true
或调用 addView(view)
手动将视图附加到 root 时,我会遇到崩溃,提示创建时无法附加视图:
ViewHolder views must not be attached when created. Ensure that you are not passing 'true' to the attachToRoot parameter of LayoutInflater.inflate(..., boolean attachToRoot)
我的问题是:这可能吗?如果不是,为什么官方文档说可以手动创建视图?
问题是您一遍又一遍地返回相同的视图。明确要求onCreateViewHolder()
每次调用时创建一个新视图。
文档说您可以手动创建视图,但这仍然意味着每次 onCreateViewHolder()
运行时您都需要手动创建不同的视图。
因此,因为您每次都是 re-using 相同的视图,所以您的应用调用 onCreateViewHolder()
的第 秒 次,视图已经附加到parent.
我想制作通用适配器,让我重新使用它。这就是为什么我决定不通过 inflating
创建视图,而是将自定义的、以前创建的视图传递给 ListAdapter
中的 ViewHolder
(RecyclerView
) in onCreateViewHolder
。根据其文档,它应该是可能的,因为它说:
You can either create a new View manually or inflate it from an XML layout file.
这是我的适配器实现:
class BaseAdapter<T, V : View>(
private val adapterConfig: AdapterConfig<T, V>,
private val onClick: (T) -> (Unit)
) : ListAdapter<T, BaseViewHolder<V>>(adapterConfig.diffCallback) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<V> {
return adapterConfig.viewHolder.apply {
itemView.setOnClickListener { onClick(getItem(adapterPosition)) }
}
}
override fun onBindViewHolder(holder: BaseViewHolder<V>, position: Int) {
adapterConfig.bind(getItem(position), holder, position)
}
}
AdapterConfig
实现 class 负责创建 ViewHolder
,它看起来像这样:
override val viewHolder: BaseViewHolder<ScorerView> = BaseViewHolder(ScorerView(context))
BaseViewHolder
class:
class BaseViewHolder<out V : View>(val v: V) : RecyclerView.ViewHolder(v)
(到现在为止没什么有趣的)
我的ScorerView
是:
class ScorerView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
init {
LayoutInflater.from(context).inflate(R.layout.item_ranking, this, false)
}
fun configure(id: String, player: String, team: String, matchSet: String, points: String, pointsAvg: String) {
idTextView.text = id
playerTextView.text = player
teamTextView.text = team
matchSetTextView.text = matchSet
pointsTextView.text = points
pointsAvgTextView.text = pointsAvg
}
}
问题是,当我将 false
传递给 inflate
函数时(没关系,因为 RecyclerView
要求项目视图未附加到根视图)然后我的小部件实例(例如 idTextView
)为空。否则,当我通过传递 true
或调用 addView(view)
手动将视图附加到 root 时,我会遇到崩溃,提示创建时无法附加视图:
ViewHolder views must not be attached when created. Ensure that you are not passing 'true' to the attachToRoot parameter of LayoutInflater.inflate(..., boolean attachToRoot)
我的问题是:这可能吗?如果不是,为什么官方文档说可以手动创建视图?
问题是您一遍又一遍地返回相同的视图。明确要求onCreateViewHolder()
每次调用时创建一个新视图。
文档说您可以手动创建视图,但这仍然意味着每次 onCreateViewHolder()
运行时您都需要手动创建不同的视图。
因此,因为您每次都是 re-using 相同的视图,所以您的应用调用 onCreateViewHolder()
的第 秒 次,视图已经附加到parent.