Ejercicio: RecyclerView usando ViewBinding en Kotlin

Uso de ViewBinding en un RecyclerView en Kotlin

Tutorial sobre RecyclerView en Kotlin:

RecyclerView en Kotlin

SuperHero.kt

data class SuperHero (
    var superhero:String,
    var publisher:String,
    var realName:String,
    var photo:String
)

SuperHeroProvider original

class SuperHeroProvider {
    companion object {
        val superHeroList = listOf<SuperHero>(
            SuperHero(
                "KotlinMan",
                "Jetbrains",
                "AristiDevs",
                "https://cursokotlin.com/wp-content/uploads/2020/09/Webp.net-compress-image.jpg"
            ),
            SuperHero(
                "Spiderman",
                "Marvel",
                "Peter Parker",
                "https://cursokotlin.com/wp-content/uploads/2017/07/spiderman.jpg"
            ),
            SuperHero(
                "Daredevil",
                "Marvel",
                "Matthew Michael Murdock",
                "https://cursokotlin.com/wp-content/uploads/2017/07/daredevil.jpg"
            ),
            SuperHero(
                "Wolverine",
                "Marvel",
                "James Howlett",
                "https://cursokotlin.com/wp-content/uploads/2017/07/logan.jpeg"
            ),
            SuperHero(
                "Batman",
                "DC",
                "Bruce Wayne",
                "https://cursokotlin.com/wp-content/uploads/2017/07/batman.jpg"
            ),
            SuperHero(
                "Thor",
                "Marvel",
                "Thor Odinson",
                "https://cursokotlin.com/wp-content/uploads/2017/07/thor.jpg"
            ),
            SuperHero(
                "Flash",
                "DC",
                "Jay Garrick",
                "https://cursokotlin.com/wp-content/uploads/2017/07/flash.png"
            ),
            SuperHero(
                "Green Lantern",
                "DC",
                "Alan Scott",
                "https://cursokotlin.com/wp-content/uploads/2017/07/green-lantern.jpg"
            ),
            SuperHero(
                "Wonder Woman",
                "DC",
                "Princess Diana",
                "https://cursokotlin.com/wp-content/uploads/2017/07/wonder_woman.jpg"
            )
        )
    }
}

SuperHeroProvider

class SuperHeroProvider {
    companion object {

        val URL = "https://dam.org.es/ficheros/"

        val superHeroList = listOf<SuperHero>(
            SuperHero(
                "KotlinMan",
                "Jetbrains",
                "AristiDevs",
                // "https://cursokotlin.com/wp-content/uploads/2020/09/Webp.net-compress-image.jpg"
                URL + "Webp.net-compress-image.jpg"
            ),
            SuperHero(
                "Spiderman",
                "Marvel",
                "Peter Parker",
                // "https://cursokotlin.com/wp-content/uploads/2017/07/spiderman.jpg"
                URL + "spiderman.jpg"
            ),
            SuperHero(
                "Daredevil",
                "Marvel",
                "Matthew Michael Murdock",
                // "https://cursokotlin.com/wp-content/uploads/2017/07/daredevil.jpg"
                URL + "daredevil.jpg"
            ),
            SuperHero(
                "Wolverine",
                "Marvel",
                "James Howlett",
                // "https://cursokotlin.com/wp-content/uploads/2017/07/logan.jpeg"
                URL + "logan.jpeg"
            ),
            SuperHero(
                "Batman",
                "DC",
                "Bruce Wayne",
                // "https://cursokotlin.com/wp-content/uploads/2017/07/batman.jpg"
                URL + "batman.jpg"
            ),
            SuperHero(
                "Thor",
                "Marvel",
                "Thor Odinson",
                // "https://cursokotlin.com/wp-content/uploads/2017/07/thor.jpg"
                URL + "thor.jpg"
            ),
            SuperHero(
                "Flash",
                "DC",
                "Jay Garrick",
                // "https://cursokotlin.com/wp-content/uploads/2017/07/flash.png"
                URL + "flash.png"
            ),
            SuperHero(
                "Green Lantern",
                "DC",
                "Alan Scott",
                // "https://cursokotlin.com/wp-content/uploads/2017/07/green-lantern.jpg"
                URL + "green-lantern.jpg"
            ),
            SuperHero(
                "Wonder Woman",
                "DC",
                "Princess Diana",
                // "https://cursokotlin.com/wp-content/uploads/2017/07/wonder_woman.jpg"
                URL + "wonder_woman.jpg"
            )
        )
    }
}

 

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"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerSuperHero"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.03" />
</androidx.constraintlayout.widget.ConstraintLayout>

item_superhero.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="wrap_content">

    <ImageView
        android:id="@+id/ivSuperHero"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@drawable/ic_launcher_background" />

    <TextView
        android:id="@+id/tvSuperHeroName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="37dp"
        android:layout_marginTop="16dp"
        android:text="TextView"
        app:layout_constraintStart_toEndOf="@+id/ivSuperHero"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tvRealName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="9dp"
        android:text="TextView"
        app:layout_constraintStart_toStartOf="@+id/tvSuperHeroName"
        app:layout_constraintTop_toBottomOf="@+id/tvSuperHeroName" />

    <TextView
        android:id="@+id/tvPublisher"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp"
        android:text="TextView"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="@+id/tvRealName" />
</androidx.constraintlayout.widget.ConstraintLayout>

SuperHeroViewHolder.kt

class SuperHeroViewHolder(view:View):RecyclerView.ViewHolder(view) {

    val superHero = view.findViewById<TextView>(R.id.tvSuperHeroName)
    val realName = view.findViewById<TextView>(R.id.tvRealName)
    val publisher = view.findViewById<TextView>(R.id.tvPublisher)
    val photo = view.findViewById<ImageView>(R.id.ivSuperHero)

    fun render (superHeroModel: SuperHero) {
        superHero.text = superHeroModel.superhero
        realName.text = superHeroModel.realName
        publisher.text = superHeroModel.publisher
    }
}

SuperHeroAdapter.kt

class SuperHeroAdapter (val superheroList:List<SuperHero>) : RecyclerView.Adapter<SuperHeroViewHolder> () {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SuperHeroViewHolder {
        val layoutInflater = LayoutInflater.from(parent.context)
        return  SuperHeroViewHolder(layoutInflater.inflate(R.layout.item_superhero, parent, false))
    }

    override fun onBindViewHolder(holder: SuperHeroViewHolder, position: Int) {
        val item = superheroList[position]
        holder.render(item)
    }

    override fun getItemCount(): Int {
        return  superheroList.size
    }
}

MainActivity.kt

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        initRecyclerView()
    }

    private fun initRecyclerView() {
        val recyclerView = findViewById<RecyclerView>(R.id.recyclerSuperHero)
        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.adapter = SuperHeroAdapter(SuperHeroProvider.superHeroList)
    }
}

 

RecyclerViewExample.zip

 

Descarga de imágenes con Glide

AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET"/>

Dependencia en build.gradle

implementation("com.github.bumptech.glide:glide:4.16.0")

SuperHeroViewHolder.kt

class SuperHeroViewHolder(view:View):RecyclerView.ViewHolder(view) {

    val superHero = view.findViewById<TextView>(R.id.tvSuperHeroName)
    val realName = view.findViewById<TextView>(R.id.tvRealName)
    val publisher = view.findViewById<TextView>(R.id.tvPublisher)
    val photo = view.findViewById<ImageView>(R.id.ivSuperHero)

    fun render (superHeroModel: SuperHero) {
        superHero.text = superHeroModel.superhero
        realName.text = superHeroModel.realName
        publisher.text = superHeroModel.publisher
        Glide.with(photo.context).load(superHeroModel.photo).into(photo)

 

Descarga de imágenes con Picasso

Añadir dependencia en build.gradle

implementation ("com.squareup.picasso:picasso:2.8")

SuperHeroViewHolder.kt

class SuperHeroViewHolder(view:View):RecyclerView.ViewHolder(view) {

    val superHero = view.findViewById<TextView>(R.id.tvSuperHeroName)
    val realName = view.findViewById<TextView>(R.id.tvRealName)
    val publisher = view.findViewById<TextView>(R.id.tvPublisher)
    val photo = view.findViewById<ImageView>(R.id.ivSuperHero)

    fun render (superHeroModel: SuperHero) {
        superHero.text = superHeroModel.superhero
        realName.text = superHeroModel.realName
        publisher.text = superHeroModel.publisher
        // Glide.with(photo.context).load(superHeroModel.photo).into(photo)
        Picasso.get().load(superHeroModel.photo).into(photo);
    }
}

 

Uso de View Binding

build.gradle

buildFeatures {
    viewBinding = true
}

SuperHeroViewHolder.kt

class SuperHeroViewHolder(view: View) : RecyclerView.ViewHolder(view) {
    val binding = ItemSuperheroBinding.bind(view)

    fun render(superHeroModel: SuperHero, onClickListener: (SuperHero) -> Unit) {
        binding.tvSuperHeroName.text = superHeroModel.superhero
        binding.tvRealName.text = superHeroModel.realName
        binding.tvPublisher.text = superHeroModel.publisher
        // Glide.with(binding.ivSuperHero.context).load(superHeroModel.photo).into(binding.ivSuperHero)
        Picasso.get().load(superHeroModel.photo).into(binding.ivSuperHero);
        itemView.setOnClickListener {
            onClickListener(superHeroModel)
        }
    }
}

SuperHeroAdapter.kt

class SuperHeroAdapter(
    private val superheroList: List<SuperHero>,
    private val onClickListener: (SuperHero) -> Unit
) : RecyclerView.Adapter<SuperHeroViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SuperHeroViewHolder {
        val layoutInflater = LayoutInflater.from(parent.context)
        return SuperHeroViewHolder(layoutInflater.inflate(R.layout.item_superhero, parent, false))
    }

    override fun onBindViewHolder(holder: SuperHeroViewHolder, position: Int) {
        val item = superheroList[position]
        holder.render(item, onClickListener)
    }

    override fun getItemCount(): Int {
        return superheroList.size
    }
}

MainActivity.kt

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        initRecyclerView()
    }

    private fun initRecyclerView() {
        val manager = LinearLayoutManager(this)
        val decoration = DividerItemDecoration(this, manager.orientation)
        binding.recyclerSuperHero.layoutManager = manager
        binding.recyclerSuperHero.adapter =
            SuperHeroAdapter(SuperHeroProvider.superHeroList) { superHero ->
                onItemSelected(
                    superHero
                )
            }
        binding.recyclerSuperHero.addItemDecoration(decoration)
    }

    fun onItemSelected(superHero: SuperHero) {
        Toast.makeText(this, superHero.superhero, Toast.LENGTH_SHORT).show()
    }
}

item_superhero.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
    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_marginHorizontal="16dp"
    android:layout_marginVertical="8dp"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/ivSuperHero"
        android:layout_width="150dp"
        android:layout_height="150dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:src="@drawable/ic_launcher_background" />

    <TextView
        android:id="@+id/tvSuperHeroName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="21sp"
        android:textStyle="bold"
        android:textColor="@color/black"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/ivSuperHero"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="KotlinMan" />

    <TextView
        android:id="@+id/tvRealName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/ivSuperHero"
        app:layout_constraintTop_toBottomOf="@+id/tvSuperHeroName"
        tools:text="Julio" />

    <TextView
        android:id="@+id/tvPublisher"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        tools:text="Hola" />


    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.cardview.widget.CardView>

 

Repositorio en GitHub

Mejora: poner un botón que permita añadir un nuevo elemento a la lista

 

Más información:

How To: RecyclerView with a Kotlin-Style Click Listener in Android

Código en GitHub

 

Ejercicio 2 de la tarea online

Deja una respuesta