Sectioned RecyclerView — Kotlin

ChandraSaiMohan bhupathi
3 min readJan 2, 2021

Introduction: This story describes about sectioned RecyclerView in Android using Kotlin in combination with JetPack components.

What is SectionedList? A sectioned list displays items in a list based on section. For instance displays list of state capitals for each country. Where country is category under which all its related state/capital info is displayed.

Screen shots: The working example that implemented section list will have final output as below :

The above example displays section wise State/capitals of a country .

Steps to implement :

To implement sectioned list we need to process received data from Server/DB in such a way that ,it is categorized as sections.

Step 1:

Create a model as below:

data class StateCapital(
val countries: List<Country>
) {
data class Country(
val country: String, // India
val states: List<State>
) {
data class State(
val capital: String, // Hyderabad
val name: String // Telangana
)
}
}

Step 2: Prepare another model that categorizes data in to Parent (section header) and child (Parent’s corresponding child info)

class ExpandableCountryModel {
companion object{
const val PARENT = 1
const val CHILD = 2

}
lateinit var countryParent: StateCapital.Country
var type : Int
lateinit var countryChild : StateCapital.Country.State
var isExpanded : Boolean
private var isCloseShown : Boolean

constructor( type : Int, countryParent: StateCapital.Country, isExpanded : Boolean = false,isCloseShown : Boolean = false ){
this.type = type
this.countryParent = countryParent
this.isExpanded = isExpanded
this.isCloseShown = isCloseShown

}


constructor(type : Int, countryChild : StateCapital.Country.State, isExpanded : Boolean = false,isCloseShown : Boolean = false){
this.type = type
this.countryChild = countryChild
this.isExpanded = isExpanded
this.isCloseShown = isCloseShown


}
}

Step 3: Process data to achieve sectioned view:

fun prepareDataForSectionedAdapter(stateCapital: StateCapital) : MutableList<ExpandableCountryModel>{
var expandableCountryModel = mutableListOf<ExpandableCountryModel>()
for (states in stateCapital.countries) {
expandableCountryModel.add(ExpandableCountryModel(ExpandableCountryModel.PARENT,states))
for(capitals in states.states){
expandableCountryModel.add(ExpandableCountryModel(ExpandableCountryModel.CHILD,capitals))
}
}
return expandableCountryModel
}

Step 4: Create a adapter to populate the view as below:

class CountryStateSectionedAdapter(var countryClickedListener: CountryClickedListener, var countryStateModelList:MutableList<ExpandableCountryModel>) :  RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var isFirstItemExpanded : Boolean = true
private var actionLock = false
lateinit var countryName:String
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when(viewType) {
ExpandableCountryModel.PARENT -> {CountryStateParentViewHolder(LayoutInflater.from(parent.context).inflate(
R.layout.expandable_parent_item, parent, false))}

ExpandableCountryModel.CHILD -> { CountryStateChildViewHolder(LayoutInflater.from(parent.context).inflate(
R.layout.expandable_child_item, parent, false)) }

else -> {CountryStateParentViewHolder(LayoutInflater.from(parent.context).inflate(
R.layout.expandable_parent_item, parent, false))}
}
}

override fun getItemCount(): Int = countryStateModelList.size

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val row = countryStateModelList[position]
when(row.type){
ExpandableCountryModel.PARENT -> {
(holder as CountryStateParentViewHolder).countryName.text = row.countryParent.country
countryName = row.countryParent.country
holder.closeImage.visibility = View.GONE
holder.upArrowImg.visibility = View.GONE

}


ExpandableCountryModel.CHILD -> {
(holder as CountryStateChildViewHolder).stateName.text = row.countryChild.name
holder.capitalImage.text = row.countryChild.capital
countryName?.let {
holder.layout.tag = it
}
holder.stateName.tag = row.countryChild
holder.layout.setOnClickListener {
var countryInfo = holder.stateName.tag
countryClickedListener.onItemClick(holder.layout.tag.toString(),
countryInfo as StateCapital.Country.State
)
}
}
}

}


override fun getItemViewType(position: Int): Int = countryStateModelList[position].type




class CountryStateParentViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
internal var layout = itemView.country_item_parent_container
internal var countryName : TextView = itemView.country_name
internal var closeImage = itemView.close_arrow
internal var upArrowImg = itemView.up_arrow

}

class CountryStateChildViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
internal var layout = itemView.country_item_child_container
internal var stateName : TextView = itemView.state_name
internal var capitalImage = itemView.capital_name

}
}

The code for the above sectioned list is available in the below Github link for reference:

--

--