Search code examples
androidkotlinandroid-recyclerviewswipeitemtouchhelper

notify onSwiped method that list is sorted in mainActivity


I am using recyclerView to show list of apps installed in device, I implement onSwipe method to perform uninstall ....along with sorting feature such as name, size etc..

Now when I sort list according to name onswipe viewholder ...doesn't refresh

Suppose in a list ...at index[1]...gallery app is there, after sorting this goes to index[10] now the problem is onSwipe method think gallery is at index[1], but actually it is displayed on index[10] in recyclerView ..

Problem occur here is when I swipe at index[1] it execute uninstall dialog of gallery but it is displayed at [10]


How to notify onSwiped method that list is sorted and every item change its index


MainActivity.kt

class MainActivity : AppCompatActivity() {

lateinit var adapter: Adapter  // create adapter instance
lateinit var applicationList:MutableList<AppData>

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    applicationList = getApps(installedApps()) // initialize applicationList variable
    recyclerView.layoutManager = LinearLayoutManager(this)
    adapter = Adapter(applicationList) // initialize adapter variable
    recyclerView.adapter = adapter // pass adapter to recyclerView

   sortList()

          // I create sepearate abstract class SwipeToDeleteCallback and call here

    val swipeHandler = object : SwipeToDeleteCallback(this) {
        override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
            currentItem = viewHolder.adapterPosition
            val packageName =
                applicationList[currentItem].packageName // get packageName from position
            val appCategory = applicationList[currentItem].category

                uninstall() // call uninstall function
        }
        
    }
    val itemTouchHelper = ItemTouchHelper(swipeHandler)
    itemTouchHelper.attachToRecyclerView(recyclerView) // attach onSwipe to recyclerView

}

fun uninstall(){
    // perform uninstall 
}

private fun installedApps(): MutableList<ResolveInfo> {
  // get installed apps
}

fun sortList() { 
    Sort_List.setOnClickListener {
        val popUp = PopupMenu(this, Sort_List)
        popUp.menuInflater.inflate(R.menu.sort_menu, popUp.menu)

        popUp.setOnMenuItemClickListener { myItem ->
            when (myItem.itemId) {
                R.id.Name_ASC -> {
                    
                    val sortedList =  applicationList.sortedBy { it.name }
                    adapter.update(sortedList)
                }
                R.id.Name_DES -> {
                    val sortedList =  applicationList.sortedByDescending { it.name }
                    adapter.update(sortedList)
                }
              }
            true
        }
        popUp.show()
    }
}


private fun getApps(List: MutableList<ResolveInfo>): MutableList<AppData> {

    // fetch all apps and return list
}

SwipeToDeleteCallback.kt

abstract class SwipeToDeleteCallback(context: Context) : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {

private val deleteIcon = ContextCompat.getDrawable(context, R.drawable.ic_delete_white)
private val intrinsicWidth = deleteIcon?.intrinsicWidth
private val intrinsicHeight = deleteIcon?.intrinsicHeight
private val background = ColorDrawable()
private val backgroundColor = Color.parseColor("#f44336")
private val clearPaint = Paint().apply { xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR) }


override fun getMovementFlags(
    recyclerView: RecyclerView,
    viewHolder: RecyclerView.ViewHolder
): Int {
    return super.getMovementFlags(recyclerView, viewHolder)
}

override fun onMove(
    recyclerView: RecyclerView,
    viewHolder: RecyclerView.ViewHolder,
    target: RecyclerView.ViewHolder
): Boolean {
    return false
}

override fun onChildDraw(
    c: Canvas,
    recyclerView: RecyclerView,
    viewHolder: RecyclerView.ViewHolder,
    dX: Float,
    dY: Float,
    actionState: Int,
    isCurrentlyActive: Boolean
) {
    val itemView = viewHolder.itemView
    val itemHeight = itemView.bottom - itemView.top
    val isCanceled = dX == 0f && !isCurrentlyActive

    if (isCanceled){
        clearCanvas(c,itemView.right + dX, itemView.top.toFloat(), itemView.right.toFloat(), itemView.bottom.toFloat())
        super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
    }

    // Draw the red delete button
   
    //Calculate position of delete icon
   
    // Draw the delete icon
    
    super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
}

private fun clearCanvas(c: Canvas?, left: Float, top: Float, right: Float, bottom: Float) {
    c?.drawRect(left, top, right, bottom, clearPaint)
}

Adapter.kt

class Adapter(private var listOfApps: MutableList<AppData>) :
RecyclerView.Adapter<Adapter.ViewHolder>() {

class ViewHolder(appView: View) : RecyclerView.ViewHolder(appView) {

    // call elements from list_apps.xml
    val icon: ImageView = appView.App_icon
    val name: TextView = appView.App_name
    val size: TextView = appView.App_size
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    val view = LayoutInflater.from(parent.context).inflate(
        R.layout.list_apps, parent, false
    )
    return ViewHolder(view)
}

override fun getItemCount() = listOfApps.size

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

    val currentItem = listOfApps[position]
    holder.icon.setImageDrawable(currentItem.icon) 
    holder.name.text = currentItem.name
    holder.size.text = currentItem.size
    
}
fun update(newList: MutableList<AppData>){
    listOfApps = newList
    notifyDataSetChanged()
  }

Solution

  • There is one problem i see in your code: you are using applicationList to get swiped item inside onSwiped but after sorting you are putting another list to adapter. there are two ways to fix this

    1. get swiped item from adaptor
    2. or use sortBy() instead of sortedBy() for sorting list

    MODIFY SNIPPET TO

    popUp.setOnMenuItemClickListener { myItem ->
            when (myItem.itemId) {
                R.id.Name_ASC -> {
                    
                    applicationList.sortBy{ it.name }
                    adapter.notifyDataSetChanged()
                }
                R.id.Name_DES -> {
                    applicationList.sortByDescending{ it.name }
                    adapter.notifyDataSetChanged()
                }
              }
            true
        }