Developer's Blog

Androidでドラッグアンドドロップ

こんにちは。
Android 開発担当の岸本です。

今回は Android でのドラッグアンドドロップの実装についてです。
※Android OS 3 系以上が対象です。


Android のアプリを開発していると、
ドラッグアンドドロップで View の並び替えをしたいという要望があります。
Android OS 2 系だと、ドラッグアンドドロップを実現する API がなく、
全て自分で実装しなくてはならず、非常に大変です。

ですが、Android OS 3 系以上だと、簡単に実装できます。

ドラッグアンドドロップを実装しよう

ドラッグアンドドロップを開始するには以下の様に実装するだけです。
ドラッグアンドドロップを開始したいタイミングで以下を実装してみてください。
通常は onLongClick に実装すればよいかと思います。

view.startDrag(null, new View.DragShadowBuilder(view), null, 0);

ドラッグアンドドロップ中のイベントは OnDragListener をセットするだけで、
受け取る事ができます。
これだけで、対象のViewのドラッグアンドドロップを実現する事できました。

Android OS 2 系までの実装と比較してみましょう。
以下のコードは同様の処理をAndroid OS 2 系で実装した場合の処理です。
moveDragItem, dropは onTouch などで呼び出しています。

	
@Override
public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       	setContentView(R.layout.main);

	mWm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
	mParams = new WindowManager.LayoutParams();
	mParams.gravity = Gravity.TOP | Gravity.LEFT;

	mParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
	mParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
	mParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
			| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
			| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
			| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
	mParams.format = PixelFormat.TRANSLUCENT;
	mParams.windowAnimations = 0;
}

@Override
public boolean onLongClick(View v) {
	v.setDrawingCacheEnabled(true);
	v.buildDrawingCache();
	mImage = new ImageView(getApplicationContext());
	mImage.setAlpha(128);
	mImage.setImageBitmap(v.getDrawingCache());
	moveDragItem();
	isDrag = true;

	return true;
}

private void moveDragItem() {
	mParams.x = (int) mPoint.x - mImage.getWidth()/2;
	mParams.y = (int) mPoint.y - mImage.getHeight()/2;

	if (!isDrag) {
	        mWm.addView(mImage, mParams);
	} else {
		mWm.updateViewLayout(mImage, mParams);
	}
}

private void drop(float x, float y){
	mWm.removeView(mImage);
	int pos = getDropPosition(x, y);
	isDrag = false;
}

Android OS 3 系以上だとコード量が大幅に減っていますね。
感動です!!

Viewを入れ替える

さて、これだけだと、選択した View をドラッグアンドドロップ出来るだけで、Viewの並び替えまでは出来ません。
並び替えも、自動で行われると非常に楽なのですが、自分で実装する必要があります。

基本はドロップした座標から、Viewを入れ替える位置を取得して、入れ替えるだけです。 サンプルでは、以下の様な実装にしました。
※getDropPositionでViewの位置を取得しています。アプリのレイアウトに合わせて実装してください。

@Override
public boolean onLongClick(View v) {
	mDragView = v;
	v.startDrag(null, new DragShadowBuilder(v), null, 0);
	mContainer.removeView(v);
	return false;
}

@Override
public boolean onDrag(View v, DragEvent event) {
	switch(event.getAction()) {
		case DragEvent.ACTION_DROP:
			int pos = getDropPosition(event.getX(), event.getY());
			mContainer.addView(mDragView, pos);
			break;
	}
	return true;
}

アニメーションを入れてみよう

このままでも、ドラッグアンドドロップでの View の並び替えができますが、ドロップ時に View の位置がぱっと切り替わってしまいます。
アニメーションさせたい時は、 LayoutTransition を使ってみましょう。
ViewGroup にセットするだけで、Viewの追加、削除時にアニメーションが行われます。
対象の View が配置されている親の ViewGroup にセットしてください。
サンプルでは親は LinearLayout にしていますので、LinearLayout にセットしています。

mContainer.setLayoutTransition(new LayoutTransition());

独自のアニメーションを使用する必要があればLayoutAnimationsが参考になると思います。

 

まだまだ、案件的には、Android OS 2系 までが多く、上記の様な実装はできませんが、
Android アプリで大変だったドラッグアンドドロップや アニメーションが簡単に実装できるようになっています。

Android OS 4.0 にアップデートされる端末も数多く発表されているので、上記の様に実装できる日は近そうですね!!


Copyright © 2019 Fenrir Inc. All rights reserved.