I have a chat RecyclerView, I want to prevent RecyclerView from auto scrolling to last item on item deleted. I want to make the smooth scroll only on activity starts.
Below, a code samples for setting up the RecyclerView and the message deleting process.
If anyone can help me. Thank you…
Setting RecyclerView
private fun setRecyclerView() {
val linearLayoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
linearLayoutManager.stackFromEnd = true
recyclerView.layoutManager = linearLayoutManager
//recyclerView.setHasFixedSize(true)
recyclerView.itemAnimator = DefaultItemAnimator()
adapter = SingleChatAdapter(this, messages, senderRoom!!, receiverRoom!!, {num ->
incDecNum(num)
}) {show, hide ->
showChosenToolbar(show, hide)
}
recyclerView.adapter = adapter
}
Delete Message
private fun delBtn() {
val delS = containerView?.findViewById<View>(R.id.deleteSelections)
delS?.setOnClickListener {
val senderDel = LayoutInflater.from(this).inflate(R.layout.sender_deletes, null)
val receiverDel = LayoutInflater.from(this).inflate(R.layout.receiver_deletes, null)
for (msg: SingleChatData in messages) {
if (msg.selected && msg.senderId == auth.uid) {
val deleteDialog = AlertDialog.Builder(this).setView(senderDel)
.setTitle("Delete This message")
val myDialog = deleteDialog?.show()
senderDel.deleteForMeS.setOnClickListener {
deleteForMe()
myDialog?.dismiss()
showChosenToolbar(false, true)
chosenNumTxt.text = "0"
adapter.notifyDataSetChanged()
}
senderDel.deleteForAllS.setOnClickListener {
deleteForAll()
myDialog?.dismiss()
showChosenToolbar(false, true)
chosenNumTxt.text = "0"
adapter.notifyDataSetChanged()
}
senderDel.cancelDeletionS.setOnClickListener { myDialog?.dismiss() }
} else if (msg.selected && msg.senderId != auth.uid) {
val deleteDialog = AlertDialog.Builder(this).setView(receiverDel)
.setTitle("Delete This message")
val myDialog = deleteDialog?.show()
receiverDel.deleteForMeR.setOnClickListener {
deleteForMe()
myDialog?.dismiss()
showChosenToolbar(false, true)
chosenNumTxt.text = "0"
adapter.notifyDataSetChanged()
}
receiverDel.cancelDeletionR.setOnClickListener { myDialog?.dismiss() }
}
}
}
}
Add data to adapter
private fun setDataToAdapter(){
firestore.collection("Chats").document(senderRoom!!).collection("messages").orderBy("time")
.addSnapshotListener { value, _ ->
if (!value?.isEmpty!!) {
messages.clear()
for (document in value.documents) {
val coMsg = document.data?.get("message").toString()
val coId = document.data?.get("senderId").toString()
val msgId = document.id
//Using Date
// Get Calendar
val calendarMap = document.data?.get("date") as Map<*, *>
val curTimestamp = calendarMap["time"] as com.google.firebase.Timestamp
val millis = curTimestamp.seconds * 1000 + curTimestamp.nanoseconds / 1000000
val ss = SimpleDateFormat("hh:mm a", Locale.getDefault())
val netCal = Date(millis)
val msgTime = ss.format(netCal).toString()
// Get Day
val chatDay = document.data?.get("day").toString()
// Get Full Date
val fullDateStamp = calendarMap["time"] as com.google.firebase.Timestamp
val dateInMillis = fullDateStamp.seconds * 1000 + fullDateStamp.nanoseconds / 1000
val sdf = SimpleDateFormat("MM/dd/yyyy", Locale.getDefault())
val netAllDate = Date(dateInMillis)
val fullDate = sdf.format(netAllDate).toString()
val type = document.data?.get("type").toString()
val coMsgT = SingleChatData(coMsg, coId, msgId, msgTime, chatDay, fullDate, type)
messages.add(coMsgT)
}
adapter.notifyDataSetChanged()
recyclerView.post { // Call smooth scroll
recyclerView.smoothScrollToPosition(adapter.itemCount - 1)
}
}
}
}
>Solution :
Instead of notifyDataSetChanged()
(which basically says "redisplay everything because something somewhere has changed in some way") you should use one of the more specific notify methods, like notifyItemRemoved
. That way the Adapter and RecylerView can be smarter about visually updating, like avoiding scrolling and adding animations.
If you’re talking about that smoothScrollToPosition
call you’re making, that looks like it happens whenever your data updated – and if I had to guess, I’d assume you’re doing those updates in deleteForMe()
and deleteForAll()
. In which case, smooth scrolling to the last item is what you’ve told it to do. If you want to avoid that, and it’s really only something that should happen once during setup, just add a flag or something:
// some top level / ViewModel property
var firstScrollDone = false
...
// in your data snapshot listener
if (!firstScrollDone) {
firstScrollDone = true
// do the scroll
}
There’s probably a better way to do it in your specific situation, but you get the idea!