0

My problem is that I want to select an item in a RecyclerView and it should change the color and if I click on another the first selected item should change to the default color (and the last clicked should have the selected color).

I have already a color change of the selected one and if I click on the selected one again it changes to default color. Now I am only missing that if I click on an unselected item and if I have already a selected item they "switch" the color

This is my SubItem class:

class SubItem(val channel: Channel) : Item<GroupieViewHolder>() {
    @SuppressLint("ResourceAsColor")
    override fun bind(viewHolder: GroupieViewHolder, position: Int) {

        val profileImageUrl =  channel.channel_logo

        viewHolder.itemView.sub_item_name.text = channel.channel_name

        viewHolder.itemView.sub_item_layout.setBackgroundResource(R.color.white)
        viewHolder.itemView.sub_item_name.setTextColor(R.color.colorSecondaryText)

        val targetImageView = viewHolder.itemView.sub_item_profile
        try {
            Picasso.get().load(profileImageUrl)
                .placeholder(R.drawable.ic_baseline_account_circle_24)
                .into(targetImageView)
        }catch (e:Exception){
            Log.d("SubItem","${e.message}")
        }

        viewHolder.itemView.sub_item_layout.setOnClickListener {
            if (selected_position == position){
                selected_position = null
                viewHolder.itemView.sub_item_layout.setBackgroundResource(R.color.white)
                viewHolder.itemView.sub_item_name.setTextColor(R.color.colorSecondaryText)
            }
            else{
                selected_position = position
                viewHolder.itemView.sub_item_layout.setBackgroundResource(R.color.colorSecondaryText)
                viewHolder.itemView.sub_item_name.setTextColor(R.color.black)
            }
        }
    }

    override fun getLayout(): Int {
        return R.layout.subscription_item
    }
}

If it is helping here is my function where I add the items to the RecyclerView

private fun fetchSubs() {
        val uid = auth.uid
        val user = database.getReference("/users/$uid/subscriptions")
        val adapter = GroupAdapter<GroupieViewHolder>()

        user.addListenerForSingleValueEvent(object : ValueEventListener{
            @SuppressLint("NotifyDataSetChanged")
            override fun onDataChange(p0: DataSnapshot) {
                p0.children.forEach{
                    val sub = it.getValue(Subscription::class.java) ?: return
                    if (sub.subscribed == true) {
                        val ref = database.getReference("/channels/${sub.channel_uid}")
                        ref.addListenerForSingleValueEvent(object : ValueEventListener {
                            override fun onDataChange(p0: DataSnapshot) {
                                val channel = p0.getValue(Channel::class.java) ?: return

                                adapter.add(SubItem(channel))
                            }
                            override fun onCancelled(error: DatabaseError) {

                            }
                        })
                    }
                }

                adapter.setOnItemClickListener{ item, view ->
                    val subItem = item as SubItem
                    val channelName = subItem.channel.channel_name
                    val channelUid = subItem.channel.uid

                    Toast.makeText(requireContext(),"$channelName : $channelUid", Toast.LENGTH_SHORT).show()

                    fetchSubs()
                }

                sub_recyclerview.adapter = adapter
            }
            override fun onCancelled(error: DatabaseError) {

            }
        })
    }

sorry that I am not using Models and Adapter

Bruno
  • 3,872
  • 4
  • 20
  • 37
Andrey
  • 55
  • 7
  • The logic that you have written is working only when user click on the item. You have to write the color set logic outside of onClick also so that correct color can be added to the item on scroll. – ahjo4321hsotuhsa Sep 14 '22 at 09:11
  • @AshutoshOjha if I write: `if (selected_position == position)} viewHolder.itemView.sub_item_layout.setBackgroundResource(R.color.colorSecondaryText) viewHolder.itemView.sub_item_name.setTextColor(R.color.black)} else{ viewHolder.itemView.sub_item_layout.setBackgroundResource(R.color.white) viewHolder.itemView.sub_item_name.setTextColor(R.color.colorSecondaryText)}` under clickListener its also not working. its just doing the same as before – Andrey Sep 14 '22 at 09:23
  • after setting selected position, call notify data change – ahjo4321hsotuhsa Sep 14 '22 at 09:38
  • @AshutoshOjha if u mean add `notifyChanged` in clickListener after the `if` and `else`. And then underneath the clickListener the code in my comment above. Unfortunately it doesn't work tried it already before asking for help – Andrey Sep 14 '22 at 09:53
  • Add a boolean isSelected to the list and onClick update this boolean in list and call notifyChange() and apply your logic on the if(list.get(position).isSelected).. else .. – ahjo4321hsotuhsa Sep 14 '22 at 10:01
  • @AshutoshOjha I tried it with a Boolean list and it doesn't work either. The problem is `notifyChanged` only updates the pressed item. – Andrey Sep 14 '22 at 12:33
  • I think you need to call two notifyChange notifyItemChanged(previousItem) and notifyItemChanged(position); or just for sake of checking use as it's not recommended way use notifyDataSetChanged(). Please try this with isSelected boolean in the list – ahjo4321hsotuhsa Sep 14 '22 at 13:54
  • @AshutoshOjha I can only use `notifyChanged` in my class SubItem. Did you once used `groupie`? – Andrey Sep 14 '22 at 14:30

1 Answers1

0

For everyone who uses groupie like me this could help you in future.

This is my solution for my Problem.

SubItem class

class SubItem(val channel: Channel) : Item<GroupieViewHolder>() {
    @SuppressLint("ResourceAsColor")
    override fun bind(viewHolder: GroupieViewHolder, position: Int) {
        val profileImageUrl =  channel.channel_logo

        viewHolder.itemView.sub_item_name.text = channel.channel_name

        val targetImageView = viewHolder.itemView.sub_item_profile

        try {
            Picasso.get().load(profileImageUrl)
                .placeholder(R.drawable.ic_baseline_account_circle_24)
                .into(targetImageView)
        }catch (e:Exception){
            Log.d("SubItem","${e.message}")
//            Toast.makeText(,e.message,Toast.LENGTH_SHORT).show()
        }

        checkFilter(viewHolder,position)
    }

    @SuppressLint("ResourceAsColor")
    private fun checkFilter(v: GroupieViewHolder, p: Int) {
        when (SubscriptionsFragment.list[p]) {
            true -> {
                v.itemView.sub_item_layout.setBackgroundResource(R.color.colorDivider)
                v.itemView.sub_item_name.setTextColor(R.color.black)
            }
            false -> {
                v.itemView.sub_item_layout.setBackgroundResource(R.color.white)
                v.itemView.sub_item_name.setTextColor(R.color.colorSecondaryText)
            }
        }
    }

    override fun getLayout(): Int {
        return R.layout.subscription_item
    }
}

My function with setOnItemClickListener

private fun fetchSubs() {
        val uid = auth.uid
        val user = database.getReference("/users/$uid/subscriptions")
        val adapter = GroupAdapter<GroupieViewHolder>()

        user.addListenerForSingleValueEvent(object : ValueEventListener{
            @SuppressLint("NotifyDataSetChanged")
            override fun onDataChange(p0: DataSnapshot) {
                list = mutableListOf()
                p0.children.forEach{
                    val sub = it.getValue(Subscription::class.java) ?: return
                    if (sub.subscribed == true) {
                        val ref = database.getReference("/channels/${sub.channel_uid}")
                        ref.addListenerForSingleValueEvent(object : ValueEventListener {
                            override fun onDataChange(p0: DataSnapshot) {
                                val channel = p0.getValue(Channel::class.java) ?: return

                                list.add(false) // created in companion object: var list =  mutableListOf<Boolean>()
                                oldList.add(false) // created in companion object: var oldlist =  mutableListOf<Boolean>()
                                adapter.add(SubItem(channel))
                            }
                            override fun onCancelled(error: DatabaseError) {

                            }
                        })
                    }
                }

                adapter.setOnItemClickListener{ item, view ->
                    val subItem = item as SubItem
                    val pos = adapter.getAdapterPosition(subItem)


                    // Here happens the magic
                    list[pos] = !list[pos] // change selected item from false to true or from true to false
                    val l = list[pos] // saving Boolean

                    list = mutableListOf()
                    oldList.forEach{ // using oldList to loop so many times I need
                        list.add(false) // setting all to false
                    }
                    if (l){ // if Boolean is true
                        list[pos] = !list[pos] // change selected item from false to true
                    }


                    val channelUid = subItem.channel.uid

                    fetchVideos(channelUid)
                    adapter.notifyDataSetChanged() // refresh all items in SubItem
                }

                try {
                    sub_recyclerview.adapter = adapter
                } catch(e:Exception){
                    Log.d("fetchSubs","${e.message}")
                }
            }
            override fun onCancelled(error: DatabaseError) {

            }
        })
    }
Andrey
  • 55
  • 7