This a solution to the RecyclerView ViewTypes Challenge in Chapter 9. Its not so good but its something. I used a Base ViewHolder so that I can use multiple ViewHolders in my adapter.
// This is a data class that will hold the list data for the crimes
data class Crime(val id: UUID = UUID.randomUUID(), var requiresPolice: Int = 2 ,var title : String = “”, var date: Date = Date(), var isSolved: Boolean = false,
var contactPolice: String = “Contact Police”)
CrimeListFragment
My Base ViewHolder, normal and serious crimeViewHolder
// A Generic ViewHolder to be implemented by other ViewHolders
abstract class BaseViewHolder<T>(itemView: View) :
RecyclerView.ViewHolder(itemView) {
abstract fun bind(crime: Crime)
}
// A ViewHolder in a RecyclerView makes reference to a view by their "itemViews" or storing them in a property called itemView
/** || FIRST VIEW HOLDER || **/
private inner class CrimeHolder(view: View)
: BaseViewHolder<Crime>(view), View.OnClickListener {
private lateinit var crime : Crime
private val titleTextView : TextView = itemView.findViewById(R.id.crime_title)
private val dateTextView : TextView = itemView.findViewById(R.id.crime_date)
// We set an onClickListener on each crime represented by their itemViews
// The itemView is the view for the entire row
init {
itemView.setOnClickListener(this)
}
// This function is added here so that our ViewHolder will do the binding work of the crimes instead of our TextViews(it is a good practice)
override fun bind(crime: Crime) {
this.crime = crime
titleTextView.text = this.crime.title
dateTextView.text = this.crime.date.toString()
}
// Since our ViewHolder implements the OnCLickListener itself, we need to implements its members,
// In this case, we need to set what will happen when our button is clicked
override fun onClick(v: View) {
Toast.makeText(context, "${crime.title} pressed!", Toast.LENGTH_SHORT).show()
}
}
// Second ViewHolder for our serious crime
/** || SECOND VIEW HOLDER || **/
private inner class SecondViewHolder(view :View)
: BaseViewHolder<Crime>(view) {
private val buttonTextView : Button = itemView.findViewById(R.id.contact_police_button)
override fun bind(crime: Crime) {
buttonTextView.apply {
text = crime.contactPolice
}
}
}
My ViewHolder Adapter
// A recyclerView does not create or hold ViewHolders by itself, rather it asks an "Adapter" to do so
// This class here sets the data the Recycler view will display through the CrimeHolder
private inner class CrimeAdapter(var crimes: List<Crime>)
: RecyclerView.Adapter<BaseViewHolder<*>>() {
val firstViewType = 0
val secondViewType = 1
// This wraps up the inflated recyclerView layout and passes to the CrimeHolder creating a new ViewHolder
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<*> {
return if (viewType == firstViewType) {
return CrimeHolder(
layoutInflater.inflate(R.layout.list_item_crime, parent, false)
)
} else {
SecondViewHolder(
layoutInflater.inflate(R.layout.serious_crime_layout, parent, false)
)
}
}
override fun getItemCount() = crimes.size // This reveals the number of items in the list of crimes
// Retrieves a viewType
override fun getItemViewType(position: Int): Int {
val crime = crimes[position]
return crime.requiresPolice
}
// This obtains crimes from a particular position from the crime list and passes it to the CrimeHolder
override fun onBindViewHolder(holder: BaseViewHolder<*>, position: Int) {
val crime = crimes[position]
holder.bind(crime)
}
}
This is it. if any Improvements please let me know