How to highlight and auto perform click on recently added item in RecyclerView

Viewed 275

I have two scenario so first one is I want to highlight and auto perform click on only recently added item in RecyclerView and second one is if user select or click on any of the item that time also that should be highlighted and clickable so this second scenario I have already implemented but I don't know how to highlight and do auto perform click on last added item on the list.

MyAdapterClass

class CarItemAdapter(
        private val activity: MainActivity,
        private val carList: ArrayList<MyEntity>,
        private val myViewModel: MyViewModel,
        private val settings: Settings
) :
        RecyclerView.Adapter<RecyclerView.ViewHolder>() {
    var listener: OnItemsClickListener? = null
    var rowIndex = 0

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val layoutInflater = LayoutInflater.from(parent.context)
        return when (viewType) {
            VIEW_TYPE_ADDITEM -> ViewHolderAddCarItem(SettingsCarAddItemTileBinding.inflate(layoutInflater, parent, false))
            VIEW_TYPE_ITEM -> ViewHolderCarItem(SettingsCarItemTileBinding.inflate(layoutInflater, parent, false))
            else -> throw IllegalArgumentException("Invalid view type")
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {

        when (holder) {
            is ViewHolderCarItem -> holder.bind(carList[position -1], position-1)
            is ViewHolderAddCarItem -> holder.bind()
        }
    }

    inner class ViewHolderAddCarItem internal constructor(private var binding: SettingsCarAddItemTileBinding) : RecyclerView.ViewHolder(binding.root) {
        fun bind() {
            binding.lifecycleOwner = activity
            binding.handler = EventHandler()
            binding.userSpecificCarSubtitle.setText(R.string.user_specific_car_subtitle)
        }

        inner class EventHandler {
            fun onItemClicked() {
                activity.showSubPage(AddVehiclePage(activity), true)
            }
        }
    }

    inner class ViewHolderCarItem internal constructor(private var binding: SettingsCarItemTileBinding) : RecyclerView.ViewHolder(binding.root) {
        fun bind(myEntity: MyEntity, position: Int) {

            binding.lifecycleOwner = activity
            val bmp = BitmapFactory.decodeByteArray(myEntity.image, 0, Objects.requireNonNull<ByteArray>(myEntity.image).size)
            binding.carImage.setImageBitmap(bmp)
            binding.carName.text = myEntity.label

            binding.layoutCar.setOnClickListener {
                listener?.onItemClick(myEntity)
                settings.carNumber = myEntity.carNumber
                settings.selectedCarType = activity.getString(R.string.settings_category_view_sub_title_for_user_specific_car)
                settings.isCarSelected = true
                rowIndex = position
                notifyDataSetChanged()
            }

            binding.deleteButton.setOnClickListener {
                GlobalScope.launch(Dispatchers.IO) { bbdCarViewModel.deleteByFinNumber(myEntity.carNumber) }
                settings.isBBDCarSelected = false
                carList.removeAt(position)
                notifyDataSetChanged()
            }

            if (rowIndex == position) {
                binding.layoutCar.setBackgroundColor(activity.getColor(R.color.petrol))
                binding.carName.setTextColor(activity.getColor(R.color.white))
            } else {
                binding.layoutCar.setBackgroundColor(activity.getColor(R.color.coolGray))
                binding.carName.setTextColor(activity.getColor(R.color.coolGray_80k))
            }
        }
    }

    override fun getItemViewType(position: Int): Int {
        return if (position == 0 && position <= carList.size) {
            VIEW_TYPE_ADDITEM
        } else VIEW_TYPE_ITEM
    }

    override fun getItemCount(): Int {
        return carList.size + 1
    }

    interface OnItemsClickListener {
        fun onItemClick(myEntity: MyEntity)
    }

    fun setWhenClickListener(listener: OnItemsClickListener) {
        this.listener = listener
    }

    companion object {
        const val VIEW_TYPE_ITEM = 0
        const val VIEW_TYPE_ADDITEM = 1
    }
}

Please help me

1 Answers

We can add placeholder to adapter class and store highlighted items in it by unique id. Then in bind function we could highlight items which have those ids:

1. Add a placeholder

We can handle active states with having a placeholder to hold highlighted items.

It could be a HashSet , the type of Long is for item id's which we'll set as stable in init block.

class CarItemAdapter(...) : ... {
...
val activeHolder: HashSet<Long> = HashSet()
    
init {
    // Represents each item in the data set with a unique indentifier
    setHasStableIds(true)
 }
...


2. Add recently added item to placeHolder

Now we've got a unique identifier for each item, and a place holder for holding the active states for highlighted items.

We want last added item be highlighted, so let's assume you're adding the new item in EventHandler's onclick method, update the mothed as below:

inner class EventHandler {
            fun onItemClicked() {
                with(activeHolder){                  
                    val lastItemId = getItemId(carList.size - 1)
                    // Remove last item's id from our holder to prevent last two items being highlighted.
                    if (contains(lastItemId)) remove(lastItemId) 
                    // Suppose we add new item to carList here
                    carList.add(newItem)
                    // add last item id of new list to the holder   
                    add(getItemId(carList.size - 1))   
                }
                notifyDataSetChanged()
                
            }
        }

In code above I we supposed that adding new Item to list is inside carList.add(newItem) , if this is not the case, wrap the with(){} block of code above around the carList.add(newCar).


3. Add and Remove items to placeholder by onClick action

Pretty straightforward this one, just a oneliner:


binding.layoutCar.setOnClickListener {
    ...
    with(activeHolder) { if (contains(itemId)) remove(itemId) else add(itemId) }
    ...
notifyDataSetChanged()
}

4. Finale; perform highlighting


    inner class ViewHolderCarItem internal constructor(private var binding: SettingsCarItemTileBinding) : RecyclerView.ViewHolder(binding.root) {
        fun bind(myEntity: MyEntity, position: Int) {
            ...

            binding.layoutCar.setOnClickListener {
                ...
                with(activeHolder) { if (contains(itemId)) remove(itemId) else add(itemId) }
                ...
                notifyDataSetChanged()
            }

            binding.deleteButton.setOnClickListener {
                   ...
            }

            // Activates last item, or item's clicked
            itemView.isActivated = activeHolder.contains(itemId)

            if(itemView.isActivated) {
                // Do anything you want by highlighted items.
            }

        }
    }


I hope this answer helped.


UPDATE

For perform click on last highlighted item:

inside onCreate() method of your activity:

lifecycle.coroutineScope.launch {
            lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
                delay(300)
                recyclerView.findViewHolderForAdapterPosition(recyclerView.size-1)?.itemView?.performClick()
           }
}

Note: for repeatOnLifecycle() method you need androidx.lifecycle:lifecycle-runtime-ktx:2.4.0-alpha01 dependency.

Related