Проведите по экрану, чтобы закрыть для RecyclerView [закрыто]

116

Раньше я использовал библиотеку SwipeToDismiss, но теперь я пытаюсь перейти на RecyclerView, и все не так очевидно, знаете ли вы какие-нибудь замены для этой библиотеки? Есть идеи, как реализовать это с нуля?

Виктор Якунин
источник
1
Я сделал небольшую библиотеку, которая использует ItemTouchHelper, чтобы упростить создание жестов для recyclerview, вы можете найти ее здесь github.com/olmur/rvtools
Алексей Муравьев

Ответы:

337

Начиная с версии 22.2.0, группа поддержки Android включила ItemTouchHelperкласс, который упрощает удаление и перетаскивание смахивания. Это может быть не так полнофункционально, как некоторые из существующих библиотек, но оно исходит непосредственно от команды Android.

  • Обновите build.gradle, чтобы импортировать v22.2. + Библиотеки RecyclerView.

    compile 'com.android.support:recyclerview-v7:22.2.+'
  • Создайте экземпляр ItemTouchHelper с соответствующим SimpleCallback

    ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
        [...]
        @Override
        public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
            //Remove swiped item from list and notify the RecyclerView
        }
    };
    
    ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);

    ** Обратите внимание, что SimpleCallback принимает направления, в которых вы хотите включить перетаскивание, и направления, которые вы хотите включить.

  • Присоединитесь к вашему RecyclerView

    itemTouchHelper.attachToRecyclerView(recyclerView);
jmcdale
источник
7
Как получить индекс прокрученного элемента?
MaTTo
37
@Orochi Путем вызова getAdapterPosition () в viewHolder.
SqueezyMo
1
Они явно не особо задумывались над дизайном этого компонента. Он работает только с RecyclerView. Для таких вещей, как закусочные, существует функция смахивания, чтобы закрыть. Более общий компонент, который можно было бы использовать с любым представлением, был бы более желанным.
AndroidDev
4
Что, если я хочу обработать случай, когда пользователь частично проводит пальцем по экрану, а затем перетаскивает вид обратно на место? По-видимому, это невозможно (?) РЕДАКТИРОВАТЬ: хорошо, это возможно, но есть очень маленький запас, в котором вы можете остаться, прежде чем представление будет перемещено при выпуске. Любое предложение?
Маттео
2
@Matteo: реализовать ItemTouchHelper.Callback и переопределить getSwipeThreshold ()
Sofi Software LLC
36
 ItemTouchHelper.SimpleCallback simpleCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {
        @Override
        public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
            return false;
        }

        @Override
        public void onSwiped(final RecyclerView.ViewHolder viewHolder, int direction) {
            final int position = viewHolder.getAdapterPosition(); //get position which is swipe

            if (direction == ItemTouchHelper.LEFT) {    //if swipe left

                AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); //alert for confirm to delete
                builder.setMessage("Are you sure to delete?");    //set message

                builder.setPositiveButton("REMOVE", new DialogInterface.OnClickListener() { //when click on DELETE
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        adapter.notifyItemRemoved(position);    //item removed from recylcerview
                        sqldatabase.execSQL("delete from " + TABLE_NAME + " where _id='" + (position + 1) + "'"); //query for delete
                        list.remove(position);  //then remove item

                        return;
                    }
                }).setNegativeButton("CANCEL", new DialogInterface.OnClickListener() {  //not removing items if cancel is done
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        adapter.notifyItemRemoved(position + 1);    //notifies the RecyclerView Adapter that data in adapter has been removed at a particular position.
                        adapter.notifyItemRangeChanged(position, adapter.getItemCount());   //notifies the RecyclerView Adapter that positions of element in adapter has been changed from position(removed element index to end of list), please update it.
                        return;
                    }
                }).show();  //show alert dialog
            }
        }
    };
    ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleCallback);
    itemTouchHelper.attachToRecyclerView(recyclerView); //set swipe to recylcerview

Здесь, в коде, если пользователь проведет пальцем влево, отобразится AlertDialog, и если пользователь выберет УДАЛИТЬ, то элемент будет удален из базы данных, а recyclerview будет обновлен, а если пользователь выберет CANCEL, то recyclerview будет таким, как есть.

Кхьяти Фатания
источник
работает хорошо .. хороший ответ.
Сагар Чавада
Потрясающие! Так легко реализовать
dianakarenms
1
Вам действительно не нужна проверка направления, так if (direction == ItemTouchHelper.LEFT) // if swipe leftкак ItemTouchHelper.SimpleCallbackона ограничена только этим направлением смахивания. Если вы хотите смахивать влево и вправо, тогда ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT)вам нужно будет проверить направление.
Джеко
1
Я обнаружил, что щелчок за пределами AlertDialog отменяет диалог, но не возвращает элемент, который я смахнул. Вы можете захватить это добавление OnCancelListener в BuilderAlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);builder.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { // stuff to put the item back } });
Джеко
1
+1 Хорошо работает. Я обнаружил, что adapter.notifyItemChanged(position);вернул пройденный элемент, а не notifyItemRemoved- что более логично, imho.
winwaed
14

возможно, вы могли бы попробовать эту библиотеку:

https://github.com/daimajia/AndroidSwipeLayout

Обновление: я только что нашел еще одну хорошую библиотеку, которую вы можете использовать с RecyclerView:

https://github.com/hudomju/android-swipe-to-dismiss-undo

Пьерпаоло Паолини
источник
Я сделал свою собственную реализацию, похожую на github.com/krossovochkin/Android-SwipeToDismiss-RecyclerView . Единственным требованием было показать тост с кнопкой «Отменить», чего нет в вашей библиотеке.
Виктор Якунин
1
Библиотека от Daimajia не поддерживает функцию смахивания для закрытия.
akohout
@raveN, я только что обновил свой ответ.
Пьерпаоло Паолини
2

Эта библиотека может быть полезной. Вы можете реализовать undoв OnDissmissиспользованииsupertoast

xcodebuild
источник
Эй, я попробую! Это основано на ответе Пьерпаоло?
Мальчик
Это просто OnTouchListener вдохновляют на этом
xcodebuild
2

Я написал библиотеку SwipeToDeleteRV, которая поддерживает функцию смахивания для удаления и отмены в представлениях ресайклера. Он основан на ItemTouchHelper и очень прост в использовании.

Надеюсь, это может быть полезно для кого-то, кто сталкивается с такими же проблемами.

Например, вы можете определить свое обычное представление ресайклера в XML-макете, плюс некоторые дополнительные атрибуты:

...
xmlns:stdrv="http://schemas.android.com/apk/res-auto"
...
<io.huannguyen.swipetodeleterv.STDRecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
stdrv:border_color="@android:color/darker_gray" // specify things like border color, border width, etc.
stdrv:delete_view_background="#cccccc"
stdrv:delete_icon="@drawable/ic_archive"
stdrv:delete_icon_height="24dp"
stdrv:delete_icon_width="24dp"
stdrv:left_delete_icon_margin="32dp"
stdrv:delete_message="@string/delete_message"
stdrv:right_delete_icon_margin="32dp"
stdrv:delete_icon_color="#000000"
stdrv:has_border="true"/>

Все атрибуты stdrv необязательны. Если вы не укажете их, будут использоваться значения по умолчанию.

Затем создайте адаптер, который является подклассом STDAdapter, убедитесь, что вы вызываете конструктор суперкласса. Что-то вроде этого:

public class SampleAdapter extends STDAdapter<String> {
public SampleAdapter(List<String> versionList) {
    super(versionList);
}

}

Затем убедитесь, что вы вызываете setupSwipeToDeleteметод для установки функции удаления смахивания вверх.

mRecyclerView.setupSwipeToDelete(your_adapter_instance, swipe_directions);

swipe_directions - это направление, в котором разрешается перемещать элементы.

Пример:

// Get your recycler view from the XML layout
mRecyclerView = (STDRecyclerView) findViewById(R.id.recycler_view);
LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
mRecyclerView.setLayoutManager(layoutManager);
mAdapter = new SampleAdapter(versions);
// allow swiping in both directions (left-to-right and right-to-left)
mRecyclerView.setupSwipeToDelete(mAdapter, ItemTouchHelper.LEFT|ItemTouchHelper.RIGHT);

Это оно! Для дополнительных настроек (например, установка разных сообщений об удалении для разных элементов, временное и окончательное удаление элементов, ...), пожалуйста, обратитесь к странице readme проекта.

H.Nguyen
источник