RecyclerView plus assign Kotlin power

It is common to create lists with recyclerview in almost every project, which take us to create Adapter and ViewHolder for every list. In some cases we go through this process too many times, when there are many lists in our app.

In this article we use Kotlin features to create simple lists in easier and faster way .

Let’s begin with introducing the results of what we will get.

recyclerView.setUp(users, R.layout.item_layout, {
nameText.text = it.name
surNameText.text = it.surname
}
)

Of course for this magic we also need kotlin android extensions.

Step 1

Let’s create an AbstractAdapter in a generic way

We need to pass to the constructor the actual list of items and layout res id


abstract class
AbstractAdapter constructor(
protected var itemList: List,
private val layoutResId: Int)
: RecyclerView.Adapter() {

class Holder(itemView: View) : RecyclerView.ViewHolder(itemView)
}

Also, we need to create our view holder extending from base ViewHolder and implement our adapter’s onBindViewHolder and onCreateViewHolder as we always do when creating recyclerview.

override fun getItemCount() = itemList.size

override fun
onCreateViewHolder(parent: ViewGroup,
viewType: Int): Holder {
val view = parent inflate layoutResId
return
Holder(view)
}

override fun onBindViewHolder(holder: Holder, position: Int) {
val item = itemList[position]
holder.itemView.bind(item)
}

protected open fun View.bind(item: ITEM) {
}

class Holder(itemView: View) : RecyclerView.ViewHolder(itemView)

And we also need to create adapter extending from our abstract adapter, don’t panic, it’s shorter, let’s name it Kadapter.

class Kadapter(items: List,
layoutResId: Int,
private val bindHolder: View.(ITEM) -> Unit)
: AbstractAdapter(items, layoutResId) {

override fun onBindViewHolder(holder: Holder, position: Int) {
holder.itemView.bindHolder(itemList[position])
}
}

Step 2

Let’s see how our advanced Adapter is going to be used:

val adapter = Kadapter(users, R.layout.item_layout) {
nameText.text = it.name
surNameText.text = it.surname
}
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(this)

We can just use it in this way, or go deeper. For that let’s move forward and add more stuff.

Superhero landing! He’s going to do a superhero landing!

Let’s create an extension to recycler view.

fun  RecyclerView.setUp(items: List,
layoutResId: Int,
bindHolder: View.(ITEM) -> Unit,
manager: RecyclerView.LayoutManager = LinearLayoutManager(this.context)): Kadapter {

return Kadapter(items, layoutResId, {
bindHolder(it)
}).apply {
layoutManager = manager
adapter = this
}
}

It will encapsulate adapter and layout manager, also we can change layout manager default implementation.

Step 3

Everything was fine so far, but if we try to click the item in the list, nothing will happen. We need to take care about that. Let’s implement onClickListener.

For that we need to add click logic in our abstract adapter. Our onCreateViewHolder becomes this.

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val view = parent inflate layoutResId
val
viewHolder = Holder(view)
val itemView = viewHolder.itemView
itemView.setOnClickListener {
val
adapterPosition = viewHolder.adapterPosition
if (adapterPosition != RecyclerView.NO_POSITION) {
onItemClick(itemView, adapterPosition)
}
}
return
viewHolder
}
protected open fun onItemClick(itemView: View, position: Int) {
}

We also need to add onClick logic to our adapter implementation and extensions we created before. The final code of kadapter looks like this:

class Kadapter(items: List,
layoutResId: Int,
private val bindHolder: View.(ITEM) -> Unit)
: AbstractAdapter(items, layoutResId) {

private var itemClick: ITEM.() -> Unit = {}

constructor
(items: List,
layoutResId: Int,
bindHolder: View.(ITEM) -> Unit,
itemClick: ITEM.() -> Unit = {}) : this(items, layoutResId, bindHolder) {
this.itemClick = itemClick
}

override fun onBindViewHolder(holder: Holder, position: Int) {
holder.itemView.bindHolder(itemList[position])
}

override fun onItemClick(itemView: View, position: Int) {
itemList[position].itemClick()
}
}

And final code for extension

fun  RecyclerView.setUp(items: List,
layoutResId: Int,
bindHolder: View.(ITEM) -> Unit,
itemClick: ITEM.() -> Unit = {},
manager: RecyclerView.LayoutManager = LinearLayoutManager(this.context)): Kadapter {
return Kadapter(items, layoutResId, {
bindHolder(it)
}, {
itemClick()
}).apply {
layoutManager = manager
adapter = this
}
}

Now let’s see what we achieved.

We can create adapter without click listener and with click listener.

recyclerView.setUp(users, R.layout.item_layout, {
nameText.text = it.name
surNameText.text = it.surname
}
)

And with click

recyclerView.setUp(users, R.layout.item_layout, {
nameText.text = it.name
surNameText.text = it.surname
}
, {
toast("Clicked ${this.name}")
})

As a bonus we can add base methods to our abstract adapter, such as add, remove, update of course using diffUtils.

The bottom line of this article is demonstrating some of the powerful features of Kotlin + Android, which makes the code more flexible. Now you can go further if interested.

Thanks for reading this article. You can find full code there.

Let’s become friends on Twitter, Github and Facebook. If you enjoyed the writings then please use the clap below to recommend this article so that others can see it.

We will also love to hear your comments and suggestions 🙂

Thanks.


RecyclerView plus assign Kotlin power was originally published in Hacker Noon on Medium, where people are continuing the conversation by highlighting and responding to this story.

Please follow and like us:
0

Gurupriyan is a Software Engineer and a technology enthusiast, he’s been working on the field for the last 6 years. Currently focusing on mobile app development and IoT.