Add swipe right to delete ListView item
Asked Answered
M

5

16

I have a ListView that uses a custom adaper (that extends BaseAdapter). How do I add the swipe to delete gesture?

I want use the same functionality the gmail application uses.

Mcreynolds answered 17/10, 2016 at 14:50 Comment(2)
You can use a library like github.com/baoyongzhang/SwipeMenuListView or github.com/chthai64/SwipeRevealLayout or github.com/daimajia/AndroidSwipeLayoutAverroes
Problem is that for implements this library i must rewrite all.....Mcreynolds
P
26

The easiest way to do this is to move your ListView over to a RecyclerView and use a GridLayoutManager with a single column. It will look the same, but allows you to swipe to dismiss using the ItemTouchHelper.

     recyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
     recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 1));

     recyclerView.setAdapter(adapter);


    ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
        @Override
        public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
            // Remove item from backing list here
            adapter.notifyDataSetChanged();
        }
    });

    itemTouchHelper.attachToRecyclerView(recyclerView);
Playa answered 17/10, 2016 at 16:32 Comment(8)
Yes, you will have to change the ListView to a RecyclerView, change the adapter base class type and then create one or more Handlers for the data.Playa
I have do it, but now i have scroll in recycleview, i don't want scroll i have already scrollview is possible remove scroll?Mcreynolds
I have solved problem of scroll, my Adapter is RecyclerView.Adapter, if i want method that return item from position How i do?Mcreynolds
i want to create my custom method delete in RecyclerView.Adapter but i have a dubt, after i have delete item from ArrayList then i call notifyDataSetChanged() or i call notifyItemRemoved() ?Mcreynolds
Removed is probably the better choice, then the adapter knows which positions it has to redraw. The notifyDataSetChanged will force it to redraw whatever is on the screen.Playa
Last question: If i want add listner on item how i can?Mcreynolds
From adapter is possible call onCreate activity?Mcreynolds
Shall also implement public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {return false;} Upvoted!Hartmann
M
1

You can use the lib ::

SwipeMenuListView

Merilyn answered 17/10, 2016 at 16:52 Comment(1)
this repo is deprecatedUnderlet
M
1

Accepted answer translated to Kotlin:

val itemTouchHelper =  ItemTouchHelper(object: ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) {
    override fun onMove(
        recyclerView: RecyclerView,
        viewHolder: RecyclerView.ViewHolder,
        target: RecyclerView.ViewHolder
    ): Boolean {
        TODO("Not yet implemented")
    }

    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
            todoListAdapter.notifyDataSetChanged()
    }

})
this.runOnUiThread {
    itemTouchHelper.attachToRecyclerView(recyclerView)
}
Milkfish answered 2/10, 2020 at 14:59 Comment(0)
M
1

A Kotlin version using a ListAdapter

all credit goes to this blog post: https://theeasiestwayy.medium.com/listadapter-and-swipe-to-delete-741e32e5f824 (which as a couple of typos in it's code examples)

abstract class ListAdapterSwipeable <T, VH: RecyclerView.ViewHolder>(
    diffCallback: DiffUtil.ItemCallback<T>
): ListAdapter<T, VH>(diffCallback) {

    private val removedItems: MutableList<T> = mutableListOf()

    fun removeItem(position: Int): T? {
        if (position >= itemCount) return null
        val item = currentList[position]
        removedItems.add(item)
        val actualList = currentList - removedItems
        if (actualList.isEmpty()) removedItems.clear()
        submit(actualList, true)
        return item
    }

    private fun submit(list: List<T>?, isLocalSubmit: Boolean) {
        if (!isLocalSubmit) removedItems.clear()
        super.submitList(list)
    }

    @CallSuper
    override fun submitList(list: List<T>?) {
        submit(list, false)
    }
}
class ItemSwipeHandler<T>(
    private val adapter: ListAdapterSwipeable<T, *>,
    private val onItemRemoved: ((item: T) -> Unit)? = null
) : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) {

    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
//        val position = viewHolder.adapterPosition  DEPRECATED!!
        val position = viewHolder.bindingAdapterPosition
        val item = adapter.removeItem(position) ?: return
        onItemRemoved?.invoke(item)
    }

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

More about it's usage see the blog article from above

Metabolize answered 8/7, 2022 at 12:1 Comment(0)
P
-4

The simplest way I have found is to use a ListView.builder in a StatefullWidget and wrap the children in a Dismissible component:

ListView.builder(
  itemCount: sampleList.length, //number of items on the list
  itemBuilder: (BuildContext context, int index) {
      return Dismissible(
        key: Key(sampleList[index]), //unique key string for each element (in this case each string is unique)
        onDismissed: (direction) {
          setState(() {
            sampleList.removeAt(index); //remove list element at given index and repaint
          });
        },
        child: child: Text('${sampleList[index]}'), //what to display form the list
      );
  },
);

you can check/copy the code bellow as a working example, and pass it as a child to a component:

import 'package:flutter/material.dart';

class DismissibleList extends StatefulWidget {
  @override
  _DismissibleListState createState() => _DismissibleListState();
}

class _DismissibleListState extends State<DismissibleList> {
  @override
  Widget build(BuildContext context) {
    List<String> sampleList = ['aa', 'bb', 'cc']; // the list of elements
    return ListView.builder(
        itemCount: sampleList.length, //number of items on the list
        itemBuilder: (BuildContext context, int index) {
            return Dismissible(
              key: Key(sampleList[index]), //unique key string for each element (in this case each string is unique)
              onDismissed: (direction) {
                setState(() {
                  sampleList.removeAt(index); //remove list element at given index and repaint
                });
              },
              child: child: Padding(
                padding: EdgeInsets.all(16.0), // just to help the visual
                child: Text('${sampleList[index]}'),
              ) //what to display form the list
            );
        },
      );
  }
}
Prochoras answered 15/3, 2020 at 17:59 Comment(1)
This is an answer for flutter. However the question targets native androidPicasso

© 2022 - 2024 — McMap. All rights reserved.