Search code examples
androidkotlinandroid-recyclerviewandroid-databinding

Change background color of selectedItem in recyclerView android databinding


How can I change the backgroudColor ofselectedItem in recyclerView adapter when I use android databinding?

this is my Adapte,and class CategoyItemClickListener is implemened for handling item clicks :

class ProgramCatAdapter(
    val mContext: Context,
    val mData: MutableList<CategoryResponse>,
    val clickListener: CategoyItemClickListener
) : RecyclerView.Adapter<ProgramCatAdapter.CategoryViewHolder>() {



    override fun onCreateViewHolder(
        parent: ViewGroup,
        viewType: Int
    ): CategoryViewHolder {
        return CategoryViewHolder.from(parent)
    }

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

    override fun onBindViewHolder(holder: CategoryViewHolder, position: Int) {
        holder.bind(
            mData[position],
            clickListener,
            position

        )


    }

    fun getItem(position: Int): CategoryResponse = mData[position]

    fun getPosition(item: CategoryResponse): Int = mData.indexOf(item)

    class CategoryViewHolder private constructor(val binding: ProgramCatHorizontalBinding) :
        RecyclerView.ViewHolder(binding.root) {



        fun bind(
            item: CategoryResponse,
            clickListener: CategoyItemClickListener,
            position: Int

        ) {
            itemView.isActivated = isSelected
            binding.item = item
            binding.position = position
            binding.clickListener = clickListener
            binding.executePendingBindings()
        }

        companion object {
            fun from(parent: ViewGroup): CategoryViewHolder {
                val layoutInflater = LayoutInflater.from(parent.context)
                val binding = ProgramCatHorizontalBinding.inflate(layoutInflater, parent, false)
                return CategoryViewHolder(binding)
            }
        }
    }
}

class CategoyItemClickListener(val clickListener: (item: CategoryResponse) -> Unit) {
    fun onClick(item: CategoryResponse) {
        clickListener(item)
    }
}

And this code is for binding adapter to recyclerView :

 private fun bindCategories(cats: MutableList<CategoryResponse>?) {


        programCatAdapter = ProgramCatAdapter(mContext!!,
            cats!!, CategoyItemClickListener {
                viewModel.setSelectedCat(it)

            })

        binding.catRecycler.layoutManager =
            LinearLayoutManager(activity!!, LinearLayoutManager.HORIZONTAL, false)

        binding.catRecycler.adapter = programCatAdapter
}

How can I have access to the position of selected Item from CategoyItemClickListener and change the bgColor of that item?


Solution

  • Here an example:

    This video might give you an overview: https://youtu.be/g8GDLOMt600 (You are not going to find a solution for this question in this video. It just gives you a nice overview about data binding, RecyclerView and ClickListener)

    You need the following files: YourFragment, fragment_your.xml, list_item

    class YourFragment : Fragment(){
    
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
    
        // Get a reference to the binding object and inflate the fragment views.
        val binding: FragmentYoutFragmentBinding = DataBindingUtil.inflate(
            inflater, R.layout.fragment_your, container, false
        )
    
        binding.lifecycleOwner = this
    
         // Very important! Otherwise the layout of the recycler view wont work
        binding.yourList.layoutManager = LinearLayoutManager(this.context)
    
        // Adapter for the RecyclerView in order to show all items
        val adapter = YourAdapter(YourListener{youtItemObeject: YourItemObject, view: 
          View ->
    
          // THIS IS THE SOLUTION
          // change selected item image, if user selects this item in the list
          view.ok_image.setImageResource(R.drawable.ok_green)
        })
    
      }
    }
    

    in list_item.xml

    <?xml version="1.0" encoding="utf-8"?>
    <layout 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">
    
    <data>
    
        <variable
            name="your_object"
            type="your_package_name.your_folder.YourObject" />
    
        <variable
            name="clickListener"
            type="your_package_name.your_folder.YourListener" />
    </data>
    
    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/constraint_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="@dimen/item_margin_horizontal"
        android:layout_marginTop="@dimen/item_margin_vertical"
        android:layout_marginEnd="@dimen/item_margin_horizontal"
        android:layout_marginBottom="@dimen/item_margin_vertical"
        android:onClick="@{(thisView) -> clickListener.onClick(your_object, thisView)}">
    
        <ImageView
            android:id="@+id/ok_image"
            ... />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    </layout>
    

    And add YourListener class into the adapter-File

    class YourAdapter(val clickListener: YourListener) :
    ListAdapter<YourObject, YourAdapter.ViewHolder>(YourDiffCallback()) {
    
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder.from(parent)
    }
    
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(getItem(position)!!, clickListener)
    }
    
    class ViewHolder private constructor(val binding: ListItemYourObjectBinding) :
        RecyclerView.ViewHolder(binding.root) {
    
        companion object {
            fun from(parent: ViewGroup): ViewHolder {
                val layoutInflater = LayoutInflater.from(parent.context)
    
                val binding = 
                  ListItemYourObjectBinding.inflate(layoutInflater, parent, false)
                return ViewHolder(binding)
            }
        }
    
        fun bind(item: YourObject, clickListener: YourListener) {
            binding.yourObject = item
            binding.clickListener = clickListener
    
            // for example
            binding.okImage.setImageRessouce(R.drawable.ok_gray)
    
            binding.executePendingBindings()
        }
      }
    }
    
    
    /**
    * Callback for calculating the diff between two non-null items in a list.
    *
    * Used by ListAdapter to calculate the minimum number of changes between and old list 
    * and a new list that's been passed to `submitList`.
    */
    class YourObjectDiffCallback : DiffUtil.ItemCallback<YourObject>() {
      override fun areItemsTheSame(oldItem: YourObject, newItem: YourObject): Boolean {
        return oldItem.yourObjectValue == newItem.yourObjectValue 
      }
    
      override fun areContentsTheSame(oldItem: YourObject, newItem: YourObject): Boolean {
        return oldItem == newItem
      }
    }
    
    /**
    * Listener for your list items
    */
    
    class YourListener(val clickListener: (yourObject: YourObject, 
      view: View) -> Unit) {
      fun onClick(yourObject: YourObject, view: View) = 
        clickListener(yourObject, view)
    }