Androidでドラッグアンドドロップを実装する

タイトルまんまです。Androidドラッグアンドドロップの実装をやってみます。
イメージはこんな感じ。

f:id:ats337:20161101220040p:plain:h240:left
画面は左右にペインを設け、左に「Move Me!」というテキストを配置します。









f:id:ats337:20161101220045p:plain:h240:left
「Move Me!」を長押しすると、ドラッグが開始します。
そのままドラッグし、右ペインにドロップします。








f:id:ats337:20161101220048p:plain:h240:left
ドロップしたら右ペインに「Move Me!」が移動します。











以下にソースコードを示します。

  • drag_and_drop.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:id="@+id/left_layout" ---①
        android:orientation="vertical">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="22sp"
            android:background="#00ffffff"
            android:text="Move Me!"
            android:id="@+id/move_text"/> ---②

    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:orientation="vertical"
        android:id="@+id/right_layout" ---③
        android:background="@color/wallet_bright_foreground_holo_dark">

    </LinearLayout>
</LinearLayout>

①LinearLayoutで左ペインを構成
 idはleft_layout
②「Move Me!」をTextViewで構成
 idはmove_text
③LinearLayoutで右ペインを構成
 idはright_layout

  • DragAndDropActivity.java
public class DragAndDropActivity extends Activity {

    private TextView tvMove;
    private LinearLayout leftLayout;
    private LinearLayout rightLayout;
    private MyDragListener listener;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.drag_and_drop);
        tvMove = (TextView) findViewById(R.id.move_text);
        leftLayout = (LinearLayout) findViewById(R.id.left_layout);
        rightLayout = (LinearLayout) findViewById(R.id.right_layout);
        tvMove.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View view) {
                ClipData data = ClipData.newPlainText("text", ((TextView)view).getText().toString());
                view.startDrag(data, new View.DragShadowBuilder(view), (Object)view, 0); // ---①
                return true;
            }
        });

        listener = new MyDragListener();
        leftLayout.setOnDragListener(listener);   ---②
        rightLayout.setOnDragListener(listener); ---②
    }


    private class MyDragListener implements View.OnDragListener {
        @Override
        public boolean onDrag(View view, DragEvent dragEvent) {  ---③
            switch (dragEvent.getAction()) {
                case DragEvent.ACTION_DRAG_STARTED: {
                    // ドラッグ開始時
                    View dragView = (View) dragEvent.getLocalState();
                    dragView.setBackgroundColor(Color.LTGRAY);
                    ((TextView)dragView).setTextColor(Color.WHITE);
                    return true;
                }
                case DragEvent.ACTION_DRAG_ENTERED: {
                    break;
                }
                case DragEvent.ACTION_DRAG_LOCATION: {
                    break;
                }
                case DragEvent.ACTION_DRAG_EXITED: {
                    break;
                }
                case DragEvent.ACTION_DROP: {
                    View dragView = (View) dragEvent.getLocalState();
                    dragView.setBackgroundColor(Color.TRANSPARENT);
                    ((TextView)dragView).setTextColor(Color.BLACK);

                    ((LinearLayout) dragView.getParent()).removeView(dragView);
                    ((LinearLayout) view).addView(dragView);
                    break;
                }
                case DragEvent.ACTION_DRAG_ENDED: {
                    // ドラッグ終了時
                    Log.v(getClass().getSimpleName(), "ACTION_DRAG_ENDED");

                    return true;
                }
            }
            return true;
        }
    }
}

①ドラッグを開始する
 「Move Me!」を長押しすることでドラッグを開始します。
 ドラッグを開始するメソッドはview#startDrag()です。
②ドラッグを受け付ける
 ドラッグを受け付けるためにはView#setOnDragListener()メソッドを呼び出し、
 OnDragListenerを実装したクラスを設定する必要があります。
 ドラッグ処理の振る舞いはOnDragListenerクラスの実装で行います。
③ドラッグ操作のリスナを実装する
 OnDragListenerを実装したMyDragListenerクラスを作ってみました。
 onDragメソッドを実装する必要があります。
 onDragメソッドには
 第1引数としてドラッグリスナを設定したView
 第2引数としてDragEventクラスのインスタンスを受け付けます。
 DragEvent#getActionメソッドでどんなイベントが発生したか判定しながら処理を実装していくことになります。