2

I'm in the process of fiddling my way to a working app using Kotlin and I have hit a roadblock when trying to implement OnClickListeners for my three buttons. I have my RecyclerView populate properly, but despite following the recommendations on this SO post (except in Kotlin) and following the documentation, though I am still having trouble getting the implementation to work.



The code below is my adapter class for the implementation.

class BrowseHabitsAdapter(private val habits: ArrayList<Habit>) :
    RecyclerView.Adapter<BrowseHabitsAdapter.ViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val itemView = LayoutInflater.from(parent.context).inflate(R.layout.habit_card, parent, false)

        return ViewHolder(itemView, object: HabitClickListener {
            override fun onDecrease(position: Int) {
                val streak = itemView.dayCounter.text.toString().toInt()
                itemView.dayCounter.text = streak.dec().toString()
            }

            override fun onIncrease(position: Int) {
                val streak = itemView.dayCounter.text.toString().toInt()
                itemView.dayCounter.text = streak.inc().toString()
            }

            override fun onEdit(position: Int) {
                TODO("Change Activity to Edit")
            }
        })


    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val currentItem = habits[position]

        holder.habitTitle.text = currentItem.title
        holder.streak.text = currentItem.streak.toString()
    }

    override fun getItemCount() = habits.size


    class ViewHolder(itemView : View, listener : HabitClickListener) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
        val habitTitle: TextView = itemView.habitTitle
        val streak: TextView = itemView.dayCounter
        val decreaseCounterButton : Button = itemView.decreaseCounterButton
        val increaseCounterButton : Button = itemView.increaseCounterButton
        val listener = listener

        init {
            decreaseCounterButton.setOnClickListener(this)
            increaseCounterButton.setOnClickListener(this)
        }

        override fun onClick(v: View?) {
            when (itemView.id) {
                itemView.decreaseCounterButton.id -> listener.onDecrease(this.layoutPosition)
                itemView.increaseCounterButton.id -> listener.onIncrease(this.layoutPosition)
            }
        }
    }

    interface HabitClickListener {
        fun onDecrease(position : Int)
        fun onIncrease(position : Int)
        fun onEdit(position : Int)
    }
}

and the following is my XML code defining one of my cards:

<?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:id="@+id/cardView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginStart="10dp"
    android:layout_marginTop="10dp"
    android:layout_marginEnd="10dp"
    app:cardBackgroundColor="#eeeeee"
    app:cardCornerRadius="10dp"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    tools:context=".MainActivity">


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <LinearLayout
            android:id="@+id/cardHeader"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/habitTitle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:layout_marginTop="10dp"
                android:layout_marginRight="10dp"
                android:text="@string/default_card_title"
                android:textSize="18sp" />

            <Space
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:layout_weight="1" />

            <ImageView
                android:id="@+id/settingsIcon"
                android:layout_width="25dp"
                android:layout_height="25dp"
                android:layout_gravity="bottom"
                android:layout_marginRight="10dp"
                app:srcCompat="@android:drawable/ic_menu_manage" />
        </LinearLayout>

        <LinearLayout
            android:id="@+id/cardControls"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:orientation="horizontal">

            <Button
                android:id="@+id/decreaseCounterButton"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="10dp"
                android:text="-"
                android:textAllCaps="false"
                android:textSize="30sp" />

            <Space
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1" />

            <TextView
                android:id="@+id/dayCounter"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="10dp"
                android:fontFamily="sans-serif-medium"
                android:text="0"
                android:textAlignment="center"
                android:textSize="30sp"
                android:textStyle="bold" />

            <Space
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1" />

            <Button
                android:id="@+id/increaseCounterButton"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="10dp"
                android:text="+"
                android:textSize="30sp" />
        </LinearLayout>

    </LinearLayout>

</androidx.cardview.widget.CardView>

Any additional explanation that can be provided as to what I did wrong and what is going on in detail would be really appreciated!

DeveloperRyan
  • 837
  • 2
  • 9
  • 22

2 Answers2

2

You are in kotlin so need to implement View.OnClickListener you can directly use setOnClickListener on any view.

Inside your ViewHolder Class:

itemView.increaseCounterButton.setOnClickListener{

       listener.onIncrease(this.layoutPosition)
 }       

itemView.decreaseCounterButton.setOnClickListener{

      listener.onDecrease(this.layoutPosition)
 } 
Krishna Sony
  • 1,286
  • 13
  • 27
  • This seems to have fixed it! Can you elaborate on the reason that you put the argument in curly braces? As far as I know `setOnClickListener` is a method so it should be taking a parameter only? I also notice in IntelliJ it lists `it: View!` next to the curly braces, I'm assuming this is the "type" of sorts, but I am not familiar with it? Could you maybe explain it a little more :)? – DeveloperRyan May 29 '20 at 04:32
  • 1
    I didn't pass as a parameter it's lambda version of setOnClickListener check this link https://antonioleiva.com/lambdas-kotlin-android/ you will understand – Krishna Sony May 29 '20 at 04:48
0

It should be view?.id instead of itemView.id

        override fun onClick(v: View?) {
            when (v?.id) {
                itemView.decreaseCounterButton.id -> listener.onDecrease(this.layoutPosition)
                itemView.increaseCounterButton.id -> listener.onIncrease(this.layoutPosition)
            }
        }

Additionally, your code with bugs. You handle HabitClickListener only update UI, when you scroll your data will be update base on habits. It means it will be revert when you scroll. Make sure streak of model Habit is var

        return ViewHolder(itemView, object: HabitClickListener {
            override fun onDecrease(position: Int) {
                habits[position].streak = habits[position].streak.dec()
                itemView.dayCounter.text = shabits[position].streak.toString()
            }

            override fun onIncrease(position: Int) {
                habits[position].streak = habits[position].streak.inc()
                itemView.dayCounter.text = shabits[position].streak.toString()
            }

            override fun onEdit(position: Int) {
                TODO("Change Activity to Edit")
            }
        })
Công Hải
  • 4,961
  • 3
  • 14
  • 20