This week we will look at how we can create lists of items in Android, making use of RecyclerView.
<androidx.recyclerview.widget.RecyclerView android:layout_width="match_parent" android:layout_height="0px" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toTopOf="parent" android:id="@+id/moduleListView"/>
// This code is in the onCreate() of the Activity val moduleListView = findViewById<RecyclerView>(R.id.moduleListView) moduleListView.layoutManager = LinearLayoutManager(this)
implementation 'androidx.recyclerview:recyclerview:1.1.0'
A RecyclerView contains:
moduleListView.adapter = MyAdapter(..)
import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.TextView import androidx.recyclerview.widget.RecyclerView // The names and descriptions to be displayed are passed as parameters to // our Adapter. class MyAdapter(val titles: List<String>, val descriptions: List<String>): RecyclerView.Adapter<RecyclerView.ViewHolder>() { // A ViewHolder is associated with a particular adapter, so it makes // sense to create the holder as an inner class of the adapter. // The ViewHolder takes the associated View as a parameter inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { // Inflate the child elements of the View and store them as properties, // so we have easy access to them later val tvName = itemView.findViewById(R.id.moduleName) as TextView val tvDescription = itemView.findViewById(R.id.moduleDescription) as TextView } // onCreateViewHolder() - called when a ViewHolder is first created. override fun onCreateViewHolder(parent: ViewGroup, viewType:Int) : RecyclerView.ViewHolder { // Inflate the XML layout and create a ViewHolder using it val layoutInflater = LayoutInflater.from(parent.context) val inflatedLayout = layoutInflater.inflate(R.layout.list_item_layout, parent, false) return MyViewHolder(inflatedLayout) } // onBindViewHolder() - called when a ViewHolder is bound to a certain item of data. override fun onBindViewHolder(holder: RecyclerView.ViewHolder, index: Int) { // Cast to our specific ViewHolder class val myViewHolder = holder as MyViewHolder // Fill the name and description within the ViewHolder to the // current elements within our two lists of data myViewHolder.tvName.text = titles[index] myViewHolder.tvDescription.text = descriptions[index] } override fun getItemCount(): Int { return titles.size } }
In onCreateViewHolder(), we inflate a layout for an individual list item within the list.
In onBindViewHolder(), we bind the appropriate data to the current list item (e.g. the elements within our lists of data corresponding to the list item index)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/moduleName" android:textSize="12pt" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/moduleDescription" android:textSize="10pt" /> </LinearLayout>
import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.TextView import androidx.recyclerview.widget.RecyclerView class MyAdapter(val titles: List<String>, val descriptions: List<String>, val callback: (Int) -> Unit): RecyclerView.Adapter<RecyclerView.ViewHolder>() { inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val tvName = itemView.findViewById(R.id.moduleName) as TextView val tvDescription = itemView.findViewById(R.id.moduleDescription) as TextView } override fun onCreateViewHolder(parent: ViewGroup, viewType:Int) : RecyclerView.ViewHolder { val layoutInflater = LayoutInflater.from(parent.context) return MyViewHolder(layoutInflater.inflate(R.layout.list_item_layout, parent, false)) } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, index: Int) { val myViewHolder = holder as MyViewHolder myViewHolder.tvName.text = titles[index] myViewHolder.tvDescription.text = descriptions[index] // Run our callback when the holder's itemView is clicked myViewHolder.itemView.setOnClickListener { callback(index) } } override fun getItemCount(): Int { return titles.size } }
https://github.com/nwcourses/NetworkCommEach list item in the RecyclerView should contain:
map()
to do this: see the additional Week 1 notes from last year.Song
class that you can use in your adapter. So your adapter should just contain a single list: a list of Song objects. You can obtain the title, artist and year from each Song in the list.
notifyDataSetChanged()
method to inform the adapter that the data has changed and it needs to be redrawn. For example:
myRecyclerView.adapter.notifyDataSetChanged()You will also need to download the Node.js based MAD song server from last year, and run it. Download from here.