I would like to make generic adapter which let me reuse it. That's why I decided to not to create view by inflating
, but pass custom, previously created view to ViewHolder
in ListAdapter
(RecyclerView
) in onCreateViewHolder
. According to its documentation it should be possible, because it says:
You can either create a new View manually or inflate it from an XML layout file.
This is my adapter implementation:
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
implementation class is reposnible for creating ViewHolder
and it's looks like this:
override val viewHolder: BaseViewHolder<ScorerView> = BaseViewHolder(ScorerView(context))
BaseViewHolder
class:
class BaseViewHolder<out V : View>(val v: V) : RecyclerView.ViewHolder(v)
(Nothing interesting until now)
My ScorerView
is:
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
}
}
The problem is that when I pass false
to inflate
function (which is ok, because RecyclerView
require to item view wasn't attached to root view) then my widget instances (idTextView
for example) is null. Otherwise when I manually attach view to root either by passing true
or by calling addView(view)
I'm getting a crash saying that view can't be attached when created:
ViewHolder views must not be attached when created. Ensure that you are not passing 'true' to the attachToRoot parameter of LayoutInflater.inflate(..., boolean attachToRoot)
My question is: is it even possible? If not, why official documentation saying that it's possible to manually create view?
This method internally calls onBindViewHolder to update the ViewHolder contents with the item at the given position and also sets up some private fields to be used by RecyclerView. This method calls onCreateViewHolder to create a new ViewHolder and initializes some private fields to be used by RecyclerView.
By default it have 5. you can increase as per your need. Save this answer.
onCreateViewHolder is called when you need a new View. If there is an available Recycled View that can be provided and be bound with new data, then onBindViewHolder is called :) 96. 96. 96.
A ViewHolder describes an item view and metadata about its place within the RecyclerView. Adapter implementations should subclass ViewHolder and add fields for caching potentially expensive findViewById results. While LayoutParams belong to the LayoutManager , ViewHolders belong to the adapter.
The problem is that you're returning the same view over and over again. It is an explicit requirement that onCreateViewHolder()
creates a new view every time it is invoked.
The documentation says that you can create the View manually, but that still means that you manually create a different view each time onCreateViewHolder()
runs.
So, because you're re-using the same view every time, the second time your app calls onCreateViewHolder()
, the view is already attached to the parent.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With