AndroidのRecyclerViewドラッグアンドドロップ

このチュートリアルでは、AndroidアプリケーションのRecyclerViewにドラッグアンドドロップの機能を実装して、その方法について説明します。以前のチュートリアルでスワイプして削除する機能について既に説明しました。

リサイクラービュードラッグアンドドロップ

RecyclerViewには、ItemTouchHelperユーティリティクラスを使用して、ドラッグアンドドロップ機能を追加することができます。実装する必要のあるItemTouchHelper.Callbackインターフェースの重要なメソッドは以下の通りです。

  • isLongPressDragEnabled – return true here to enable long press on the RecyclerView rows for drag and drop.
  • isItemViewSwipeEnabled – This is used to enable or disable swipes. In this tutorial, we’ll disable this.
  • getMovementFlags – Here we pass the flags for the directions of drag and swipe. Since swipe is disable we pass 0 for it.
  • onMove – Here we set the code for the drag and drop. onSwipe – Here we implement the code for swiping. We’ll keep this empty in the current tutorial.
  • onSelectedChanged – Based on the current state of the RecyclerView and whether it’s pressed or swiped, this method gets triggered. Here we can customize the RecyclerView row. For example, changing the background color.
  • clearView – This method gets triggered when the user interaction stops with the RecyclerView row.

「RecyclerViewのドラッグアンドドロップ機能を使って、Androidアプリの作成を始めましょう。」

プロジェクトの構造

コード

以下のコードは、RecyclerViewのみを含むactivity_main.xmlレイアウトのコードです。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layoutManager="android.support.v7.widget.LinearLayoutManager" />


</LinearLayout>

MainActivity.javaのコードは以下の通りです。

package com.scdev.androidrecyclerviewdraganddrop;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    RecyclerView recyclerView;
    RecyclerViewAdapter mAdapter;
    ArrayList<String> stringArrayList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        recyclerView = findViewById(R.id.recyclerView);

        populateRecyclerView();
    }

    private void populateRecyclerView() {
        stringArrayList.add("Item 1");
        stringArrayList.add("Item 2");
        stringArrayList.add("Item 3");
        stringArrayList.add("Item 4");
        stringArrayList.add("Item 5");
        stringArrayList.add("Item 6");
        stringArrayList.add("Item 7");
        stringArrayList.add("Item 8");
        stringArrayList.add("Item 9");
        stringArrayList.add("Item 10");

        mAdapter = new RecyclerViewAdapter(stringArrayList);

        ItemTouchHelper.Callback callback =
                new ItemMoveCallback(mAdapter);
        ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
        touchHelper.attachToRecyclerView(recyclerView);

        recyclerView.setAdapter(mAdapter);
    }

}

以下では、私たちはRecyclerViewAdapter.javaクラスにStringのArrayListを配置しました。RecyclerViewにItemMoveCallback.javaクラスのインスタンスをアタッチしてドラッグアンドドロップを開始します。それぞれのファイルを見てみましょう。ItemMoveCallback.javaクラスのコードは以下の通りです。

package com.scdev.androidrecyclerviewdraganddrop;

import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;

public class ItemMoveCallback extends ItemTouchHelper.Callback {

    private final ItemTouchHelperContract mAdapter;

    public ItemMoveCallback(ItemTouchHelperContract adapter) {
        mAdapter = adapter;
    }

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

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



    @Override
    public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int i) {

    }

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

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

    @Override
    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder,
                                  int actionState) {


        if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
            if (viewHolder instanceof RecyclerViewAdapter.MyViewHolder) {
                RecyclerViewAdapter.MyViewHolder myViewHolder=
                        (RecyclerViewAdapter.MyViewHolder) viewHolder;
                mAdapter.onRowSelected(myViewHolder);
            }

        }

        super.onSelectedChanged(viewHolder, actionState);
    }
    @Override
    public void clearView(RecyclerView recyclerView,
                          RecyclerView.ViewHolder viewHolder) {
        super.clearView(recyclerView, viewHolder);

        if (viewHolder instanceof RecyclerViewAdapter.MyViewHolder) {
            RecyclerViewAdapter.MyViewHolder myViewHolder=
                    (RecyclerViewAdapter.MyViewHolder) viewHolder;
            mAdapter.onRowClear(myViewHolder);
        }
    }

    public interface ItemTouchHelperContract {

        void onRowMoved(int fromPosition, int toPosition);
        void onRowSelected(RecyclerViewAdapter.MyViewHolder myViewHolder);
        void onRowClear(RecyclerViewAdapter.MyViewHolder myViewHolder);

    }

}

ここでは、ItemTouchHelperContractというインターフェースを定義しました。その各メソッドは、ItemTouchHelper.Callbackインターフェースの実装されたメソッドから呼び出されます。RecyclerViewAdapter.javaクラスのコードは以下の通りです。

package com.scdev.androidrecyclerviewdraganddrop;

import android.graphics.Color;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Collections;

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.MyViewHolder> implements ItemMoveCallback.ItemTouchHelperContract {

    private ArrayList<String> data;

    public class MyViewHolder extends RecyclerView.ViewHolder {

        private TextView mTitle;
        View rowView;

        public MyViewHolder(View itemView) {
            super(itemView);

            rowView = itemView;
            mTitle = itemView.findViewById(R.id.txtTitle);
        }
    }

    public RecyclerViewAdapter(ArrayList<String> data) {
        this.data = data;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.cardview_row, parent, false);
        return new MyViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        holder.mTitle.setText(data.get(position));
    }


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


    @Override
    public void onRowMoved(int fromPosition, int toPosition) {
        if (fromPosition < toPosition) {
            for (int i = fromPosition; i < toPosition; i++) {
                Collections.swap(data, i, i + 1);
            }
        } else {
            for (int i = fromPosition; i > toPosition; i--) {
                Collections.swap(data, i, i - 1);
            }
        }
        notifyItemMoved(fromPosition, toPosition);
    }

    @Override
    public void onRowSelected(MyViewHolder myViewHolder) {
        myViewHolder.rowView.setBackgroundColor(Color.GRAY);

    }

    @Override
    public void onRowClear(MyViewHolder myViewHolder) {
        myViewHolder.rowView.setBackgroundColor(Color.WHITE);

    }
}


ドラッグアンドドロップが終了したとき、先に定義されたContractインターフェース内のonRowMovedが呼び出されます。そこで、ArrayListにある2つの行の位置を交換し、notifyItemMovedを呼び出してアダプターを更新します。上記のアプリケーションの出力は以下の通りです:これまでに、RecyclerViewの行のどこでも押してドラッグアンドドロップを行ってきました。次に、RecyclerViewの行内の特定のビューを押すことで同じ操作を行う方法を見ていきます。

ハンドルを使ったドラッグアンドドロップ

特定のハンドルビューを使用してドラッグアンドドロップを行うためには、以下のことを行う必要があります。デフォルトのドラッグアンドドロップを無効にするために、isLongPressDragEnabledをfalseに設定します。次に、以下のようなインターフェースを作成します。

public interface StartDragListener {
    void requestDrag(RecyclerView.ViewHolder viewHolder);
}

MainActivityで実装し、それをアダプターに渡してください。

@Override
    public void requestDrag(RecyclerView.ViewHolder viewHolder) {
        touchHelper.startDrag(viewHolder);
    }
mAdapter = new RecyclerViewAdapter(stringArrayList,this);

RecyclerViewAdapter.javaの中で次のことをしてください。

holder.imageView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() ==
                        MotionEvent.ACTION_DOWN) {
                    mStartDragListener.requestDrag(holder);
                }
                return false;
            }
        });

このチュートリアルの最後に、ダウンロードリンクに最新のコードがあります。最新のコードを使用したアプリケーションの出力は以下の通りです。このチュートリアルはこれで終わりです。プロジェクトの完全なソースコードは以下に示されています。

アンドロイドのリサイクルビュードラッグアンドドロップ

以下のGithubプロジェクトリンクを日本語で要約してください。

コメントを残す 0

Your email address will not be published. Required fields are marked *