I'm trying to learn how to code for android devices. I'm following a tutorial video to make a simple todo app. The code I have written thus far (that is relevant to this issue) is an xml file called item_todo.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" android:layout_width="match_parent" android:layout_height="80dp" android:paddingStart="8dp" android:paddingEnd="8dp"> <TextView android:id="@ id/tvTodoTitle" android:layout_width="0dp" android:layout_height="wrap_content" android:text="Example" android:textSize="24sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@ id/cbDone" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <CheckBox android:id="@ id/cbDone" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
and the todoadapter.kt file as follows:
package com.example.todo import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView class TodoAdapter ( private val todos: MutableList<Todo> ) : RecyclerView.Adapter<TodoAdapter.TodoViewHolder>(){ class TodoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder { return TodoViewHolder( LayoutInflater.from(parent.context).inflate( R.layout.item_todo, parent, false ) ) } override fun onBindViewHolder(holder: TodoViewHolder, position: Int) { val curTodo = todos[position] holder.itemView.apply { tvTodoTitle.text = curTodo.title } } override fun getItemCount(): Int { return todo.size } }
the only issue I've had thus far is that when I call:
holder.itemView.apply { tvTodoTitle.text = curTodo.title }
the holder doesn't seem to find the xml file info. Is the video I'm watching just so old the command is depreciated, or have I done something wrong?
CodePudding user response:
This is the same issue as in this question, except that the answers there don't talk about how to get view references in a ViewHolder (they only mention Fragment or Activity). So you can read the answers there for the explanation of why this isn't working any more according to the outdated tutorial instructions.
For working with a ViewHolder, here are two ways to do it without synthetic references.
Without view binding
Add properties to your view holder class for each View you want to be able to work with, and use findViewById
on the itemView
to initialize them:
class TodoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val tvTodoTitle: TextView = itemView.findViewById(R.id.tvTodoTitle)
}
Then in onBindViewHolder
, you can use it like this (notice we don't work with itemView
):
override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
val curTodo = todos[position]
holder.apply {
tvTodoTitle.text = curTodo.title
}
}
With view binding
This is preferable, especially if you have more than one view to work with in your layout, because you don't have to manually create properties for each of them and hook them up correctly to the right view IDs.
Set up view binding in your project according to the directions. Change your ViewHolder class to have a binding property like this:
class TodoViewHolder(val binding: ItemTodoBinding): RecyclerView.ViewHolder(binding.root)
And change onCreateViewHolder()
to use inflate the binding like this:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder {
return TodoViewHolder(
ItemTodoBinding.inflate(
LayoutInflater.from(parent.context),
R.layout.item_todo,
parent,
false
)
)
}
And then you can use it in onBindViewHolder
like this:
override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
val curTodo = todos[position]
holder.binding.apply {
tvTodoTitle.text = curTodo.title
}
}