RecyclerView en Kotlin
Creación de un RecyclerView en Kotlin
Ejercicio: Crear un RecyclerView de contactos
Using the RecyclerView
Using a RecyclerView
has the following key steps:
- Define a model class to use as the data source
- Add a
RecyclerView
to your activity to display the items - Create a custom row layout XML file to visualize the item
- Create a
RecyclerView.Adapter
andViewHolder
to render the item - Bind the adapter to the data source to populate the
RecyclerView
Modelo: Contact.kt
class Contact(val name: String, val isOnline: Boolean) { companion object { private var lastContactId = 0 @JvmStatic fun createContactsList(numContacts: Int): ArrayList<Contact> { val contacts = ArrayList<Contact>() for (i in 1..numContacts) { contacts.add(Contact("Person " + ++lastContactId, i <= numContacts / 2)) } return contacts } } }
Create the RecyclerView within Layout
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/addContact" android:layout_width="320dp" android:layout_height="50dp" android:layout_marginTop="16dp" android:text="@string/a_adir_contacto" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <androidx.recyclerview.widget.RecyclerView android:id="@+id/rvContacts" android:layout_width="378dp" android:layout_height="636dp" android:layout_marginTop="1dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.515" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/addContact" app:layout_constraintVertical_bias="0.3" /> </androidx.constraintlayout.widget.ConstraintLayout>
Creating the Custom Row Layout
item_contact.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingTop="10dp" android:paddingBottom="10dp" > <TextView android:id="@+id/contact_name" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" /> <Button android:id="@+id/message_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="16dp" android:paddingRight="16dp" android:textSize="10sp" tools:ignore="SpeakableTextPresentCheck" /> </LinearLayout>
Creating the RecyclerView Adapter
ContactsAdapter.kt
class ContactsAdapter // Pass in the contact array into the constructor ( // Store a member variable for the contacts private val mContacts: List<Contact> ) : RecyclerView.Adapter<ContactsAdapter.ViewHolder>() { /***** Creating OnItemClickListener */ // Define the listener interface interface OnItemClickListener { fun onItemClick(itemView: View?, position: Int) } // Define listener member variable private lateinit var listener: OnItemClickListener // Define the method that allows the parent activity or fragment to define the listener fun setOnItemClickListener(listener: OnItemClickListener) { this.listener = listener } // Provide a direct reference to each of the views within a data item // Used to cache the views within the item layout for fast access inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { // Your holder should contain a member variable // for any view that will be set as you render a row var nameTextView: TextView var messageButton: Button // We also create a constructor that accepts the entire item row // and does the view lookups to find each subview init { // Stores the itemView in a public final member variable that can be used // to access the context from any ViewHolder instance. nameTextView = itemView.findViewById<View>(R.id.contact_name) as TextView messageButton = itemView.findViewById<View>(R.id.message_button) as Button //messageButton.setOnClickListener(this); // Setup the click listener itemView.setOnClickListener { // Triggers click upwards to the adapter on click if (listener != null) { val position = adapterPosition if (position != RecyclerView.NO_POSITION) { listener.onItemClick(itemView, position) } } } } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val context = parent.context val inflater = LayoutInflater.from(context) // Inflate the custom layout val contactView = inflater.inflate(R.layout.item_contact, parent, false) // Return a new holder instance return ViewHolder(contactView) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { // Get the data model based on position val contact = mContacts[position] // Set item views based on your views and data model val textView = holder.nameTextView textView.text = contact.name val button = holder.messageButton button.text = if (contact.isOnline) "Message" else "Offline" button.isEnabled = contact.isOnline } override fun getItemCount(): Int { return mContacts.size } }
Binding the Adapter to the RecyclerView
class MainActivity : AppCompatActivity() { lateinit var contacts: ArrayList<Contact> lateinit var rvContacts: RecyclerView lateinit var addMoreButton: Button override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) rvContacts = findViewById<View>(R.id.rvContacts) as RecyclerView addMoreButton = findViewById<View>(R.id.addContact) as Button // Initialize contacts contacts = createContactsList(20) // Create adapter passing in the sample user data val adapter = ContactsAdapter(contacts) // Attach the adapter to the recyclerview to populate items rvContacts.adapter = adapter // Set layout manager to position the items rvContacts.layoutManager = LinearLayoutManager(this) adapter.setOnItemClickListener(object : ContactsAdapter.OnItemClickListener { override fun onItemClick(view: View?, position: Int) { val name = contacts[position].name Toast.makeText(this@MainActivity, "$name was clicked!", Toast.LENGTH_SHORT).show() } }) addMoreButton.setOnClickListener { // record this value before making any changes to the existing list val curSize = adapter.itemCount // Add a new contact // contacts.add(0, new Contact("Barney", true)); // Notify the adapter that an item was inserted at position 0 // adapter.notifyItemInserted(0); contacts.add(curSize, Contact("Barney", true)) adapter.notifyItemInserted(curSize) } // That's all! } }
Notifying the Adapter
// Add a new contact contacts.add(0, Contact("Barney", true)) // Notify the adapter that an item was inserted at position 0 adapter.notifyItemInserted(0)
Añadir al final de la lsita un nuevo contacto
val curSize = adapter.itemCount // Add a new contact // contacts.add(0, new Contact("Barney", true)); // Notify the adapter that an item was inserted at position 0 // adapter.notifyItemInserted(0); contacts.add(curSize, Contact("Barney", true)) adapter.notifyItemInserted(curSize)
Attaching Click Handlers using Listeners
Añadir la interface OnItemClickListener en ContactsAdapter.kt
/***** Creating OnItemClickListener */ // Define the listener interface interface OnItemClickListener { fun onItemClick(itemView: View?, position: Int) } // Define listener member variable private lateinit var listener: OnItemClickListener // Define the method that allows the parent activity or fragment to define the listener fun setOnItemClickListener(listener: OnItemClickListener) { this.listener = listener }
Añadir el listener al itemView en la clase ViewHolder en ContactsAdapter.kt
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { // Your holder should contain a member variable // for any view that will be set as you render a row var nameTextView: TextView var messageButton: Button // We also create a constructor that accepts the entire item row // and does the view lookups to find each subview init { // Stores the itemView in a public final member variable that can be used // to access the context from any ViewHolder instance. nameTextView = itemView.findViewById<View>(R.id.contact_name) as TextView messageButton = itemView.findViewById<View>(R.id.message_button) as Button //messageButton.setOnClickListener(this); // Setup the click listener itemView.setOnClickListener { // Triggers click upwards to the adapter on click if (listener != null) { val position = adapterPosition if (position != RecyclerView.NO_POSITION) { listener.onItemClick(itemView, position) } } } } }
Añadir el listener al adapter en el MainActivity.kt
adapter.setOnItemClickListener(object : ContactsAdapter.OnItemClickListener { override fun onItemClick(view: View?, position: Int) { val name = contacts[position].name Toast.makeText(this@MainActivity, "$name was clicked!", Toast.LENGTH_SHORT).show() } })
Mejora: Utilizar ViewBinding en el MainActivity y en el adapter
Deja una respuesta
Lo siento, debes estar conectado para publicar un comentario.