Double list RecyclerView

The example

In this case, as an example, I will use a football statistics app. We have two lists that we want to display with a single RecyclerView, the scorer list and the league general table list.

  • We create our adapter receiving in the constructor the two lists that we are going to show.
class StatsAdapter(private val scorers: List<Scorer>, private val teams: List<Team>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
...
}
  • We implement getItemCount() by adding the size of the two lists and returning the total.
override fun getItemCount() = scorers.size + teams.size
  • We override the getItemViewType() method to develop the logic that will help us know which list the object belongs to.
  • First, we must validate if the received position corresponds to the list of scorers, to know this we validate if the position is less than the size of the list of scorers and return a ScorersHolder.VIEW_TYPE.
  • Then we must recalculate the position we receive, to understand this part we must remember that in the getItemViewType() method we are receiving the position as if we were handling only one list and that the size of that list is defined in the getItemCount() method.
  • So, suppose the size of the first list (scorers) is 3, and we already iterate all the elements of that list, in the getItemViewType() method we would be receiving position number 3 but we must iterate the second list (teams) from position 0 to show all the elements and avoid a possible IndexOutOfBoundsException.
  • Once the position has been recalculated, we must do the same validation as for the first list and if this is true we return a TeamsHolder.VIEW_TYPE.
  • Finally, and probably unnecessary, we return a -1 in case none of the conditions are met.
override fun getItemViewType(position: Int): Int {    if (position < scorers.size) {
return ScorersHolder.VIEW_TYPE
}

val realPosition = (position - scorers.size)
if (realPosition < teams.size) {
return TeamsHolder.VIEW_TYPE
}

return -1
}
  • We need to inflate the view and create the corresponding ViewHolder instance according to the view type we receive as a parameter.
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {

return if (viewType == ScorersHolder.VIEW_TYPE) {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_scorers_list, parent, false)
ScorersHolder(view)
} else {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_teams_list, parent, false)
TeamsHolder(view)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {    when (holder) {
is ScorersHolder -> holder.bind(scorers[position])
is TeamsHolder -> holder.bind(teams[(position - scorers.size)])
}
}

Github

Credits

Icons made by Smashicons from Flaticon.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store