Search code examples
androidkotlinandroid-recyclerviewandroid-architecture-navigation

Navigation.createNavigateOnClickListener from onBindViewHolder?


I want to set an onclicklistener in the onBindViewHolder in order to navigate to a different fragment and send along some data to that fragment.

For the life of me, I can't seem to find a way to make it work. Any and all help is greatly appreciated!

The adapter class:

class ListAdapter(private val list: List<Workout>): RecyclerView.Adapter<WorkoutViewHolder>() {

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

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WorkoutViewHolder {
        val layoutInflater = LayoutInflater.from(parent.context)
        return WorkoutViewHolder(layoutInflater, parent)
    }

    override fun onBindViewHolder(holder: WorkoutViewHolder, position: Int) {
        val workout: Workout = list[position]
        holder.itemView.setOnClickListener{
            Toast.makeText(holder.itemView.context, "TEST", Toast.LENGTH_LONG).show()
            val id = workout.workoutId
            val bundle = Bundle()
            bundle.putInt("workoutId", id)
            Navigation.createNavigateOnClickListener(R.id.workoutDetailsFragment)
        }
        holder.bind(workout)
    }
}

I can get the toast to pop up, so the onclicklistener seems to be working. However, the navigation part does not work. If I just set a button inside the fragment that is hosting the recyclerview and add button.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.workoutDetailsFragment)) it can navigate just fine. So the problem seems to be calling the navigate function from inside the onclicklistener inside the onbindviewholder


Solution

  • Navigation.createNavigateOnClickListener() creates an OnClickListener. Creating an OnClickListener just to never set it on anything doesn't do anything.

    Instead, you'll want to just trigger your navigate() call directly, doing the same one line of code that createNavigateOnClickListener does internally:

    override fun onBindViewHolder(holder: WorkoutViewHolder, position: Int) {
        val workout: Workout = list[position]
        holder.itemView.setOnClickListener{
            Toast.makeText(holder.itemView.context, "TEST", Toast.LENGTH_LONG).show()
            val id = workout.workoutId
            val bundle = Bundle()
            bundle.putInt("workoutId", id)
    
            // Using the Kotlin extension in the -ktx artifacts
            // Alternatively, use Navigation.findNavController(holder.itemView)
            holder.itemView.findNavController().navigate(
                R.id.workoutDetailsFragment, bundle)
        }
        holder.bind(workout)
    }