Реализация Drag&Drop и Swipe to Delete в Android

Добавлено: 25/10/2018 18:25 |  Обновлено: 25/10/2018 18:27 |  Добавил: nick |  Просмотры: 85 Комментарии: 1
Вводная часть
В этом материале показано как реализовать Drag&Drop и Swipe to Delete для элементов списка карточек (CardView) в контейнере RecyclerView.
В первую очередь создайте проект.

Когда я работал над материалом я использовал шаблон с кнопкой fab (Blank Activity), но в последствии она мне не пригодилась, поэтому потом я ее удалил. Вы можете сразу же выбрать шаблон без кнопки — Empty Activity.

Вот как выглядит готовый пример: Здесь список карточек CardView находится в контейнере RecyclerView. Каждую карточку можно перемещать вверх и вниз, нажав на кнопку «DRAG ME UP AND DOWN», или длительно нажав на саму карточку. Можно потом будет отключить какой-то из этих двух способов в коде. Каждую карточку можно также удалить свайпнув влево или право.

Xml-файл содержимого самой карточки у меня называется item_main.xml и выглядит следующим образом:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/cv"
    android:layout_margin="5dp"
    card_view:cardCornerRadius="4dp"
    >

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="16dp">
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/title"
            android:textSize="30sp"
            android:text=" " />

        <Button
            android:id="@+id/button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="moveCard"
            android:text="Drag Me Up And Down" />
    </LinearLayout>

</android.support.v7.widget.CardView>
Код для RecyclerView следующий:
<android.support.v7.widget.RecyclerView
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:id="@+id/rv"
    >
</android.support.v7.widget.RecyclerView>
Код для RecyclerView можно вставить или в файл content_main.xml или напрямую в activity_main.xml.

С разметкой все, теперь перейдем к java-файлам.

Для работы примера потребуется 3 java-файла: MainActivity.java, RecyclerListAdapter.java и SimpleItemTouchHelperCallback.java.

MainActivity.java

В метод onCreate() добавьте следующий код:
RecyclerListAdapter adapter = new RecyclerListAdapter(this);

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.rv);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));

callback = new SimpleItemTouchHelperCallback(adapter);
mItemTouchHelper = new ItemTouchHelper(callback);
mItemTouchHelper.attachToRecyclerView(recyclerView);

После чего добавьте еще один метод:

public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
    mItemTouchHelper.startDrag(viewHolder);
}
Он потребуется для обработки события перемещения карточки по нажатию кнопки «DRAG ME UP AND DOWN».

RecyclerListAdapter.java

Содержимое этого класса привожу полностью:
public class RecyclerListAdapter extends RecyclerView.Adapter<RecyclerListAdapter.ItemViewHolder>{

    private static final String[] STRINGS = new String[]{
            "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten"
    };

    private final List<String> mItems = new ArrayList<>();

    private MainActivity mainActivity;

    public RecyclerListAdapter(MainActivity mainActivity) {
        mItems.addAll(Arrays.asList(STRINGS));
        this.mainActivity = mainActivity;
    }

    @Override
    public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_main, parent, false);
        ItemViewHolder itemViewHolder = new ItemViewHolder(view);
        return itemViewHolder;
    }

    @Override
    public void onBindViewHolder(final ItemViewHolder holder, int position) {
        holder.textView.setText(mItems.get(position));

        holder.button.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
                    mainActivity.onStartDrag(holder);
                }
                return false;
            }
        });
    }

    public void onItemDismiss(int position) {
        mItems.remove(position);
        notifyItemRemoved(position);
    }

    public void onItemMove(int fromPosition, int toPosition) {
        String prev = mItems.remove(fromPosition);
        mItems.add(toPosition > fromPosition ? toPosition - 1 : toPosition, prev);
        notifyItemMoved(fromPosition, toPosition);
    }

    @Override
    public int getItemCount() {
        return mItems.size();
    }

    public class ItemViewHolder extends RecyclerView.ViewHolder {

        public final TextView textView;
        public final Button button;

        public ItemViewHolder(View itemView) {
            super(itemView);
            textView = (TextView) itemView.findViewById(R.id.title);
            button = (Button) itemView.findViewById(R.id.button);
        }
    }
}
Здесь за обработку перетаскивания по нажатию кнопки отвечает следующий участок кода:
holder.button.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
            mainActivity.onStartDrag(holder);
        }
        return false;
    }
});
Как вы можете видеть в коде вызывается метод, который мы добавили в MainActivity.java — onStartDrag().

SimpleItemTouchHelperCallback.java

Содержимое класса следующее:
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {

    private final RecyclerListAdapter mAdapter;

    public SimpleItemTouchHelperCallback(RecyclerListAdapter adapter) {
        mAdapter = adapter;
    }

    @Override
    public boolean isLongPressDragEnabled() {
        return true;
    }

    @Override
    public boolean isItemViewSwipeEnabled() {
        return true;
    }

    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
        final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
        return makeMovementFlags(dragFlags, swipeFlags);
    }

    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
        mAdapter.onItemMove(source.getAdapterPosition(), target.getAdapterPosition());
        return true;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int i) {
        mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
    }
}
Здесь можно отключить обработку события перемещения по долгому нажатию карточки, поменяв true на false:
@Override
public boolean isLongPressDragEnabled() {
    return true;
}
На этом все. Пример готов :)

Комментарии

  • 16/11/2018 17:13 Denis Kozachenko пишет:

    Отличный туториал, благодарю!


Оставьте свой комментарий