Androidでドラッグ・アンド・ドロップ
Canvasを使わないでドラッグアンドドロップする方法
Canvasを使わない利点
- layoutをxmlでかける
- onDrawとか使わなくて済む
- どんなViewでも動かせる
- Viewのイベントを発生することができる。(アニメーションの連携とか)
- Viewを重ねることができる
- 重なったViewでイベントを発行できる(OnCLickとか)
Tip
- FrameLayoutでVIewを重ねる
※実際他のLayoutでもできるけど、こっちの方が実装しやすい
- Viewの絶対座標はView#getGrobalRectで取得
- TouchEventリスナーは動かしたいViewだけ実装
- タッチポイントの絶対座標はgetRowX,Y
- Drag中の描画座標は前回の座標の差分を計算
- Viewの表示位置はView#layoutで設定
サンプルアプリ
- ドラッグアンドドロップ可能なImageViewを作成
- Viewにアニメーションを設定
- dropのタイミングでアニメーション実行
- ドロップしたところにボタンがあったらonClickする
- ドロップのタイミングでperformClickを実行するとアニメーション中に画面遷移するので、Animationリスナーを実装して、アニメーション終了のタイミングでperformClickを実行する
ソース
■main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/layout"> <FrameLayout android:id="@+id/FrameLayout01" android:background="#333333" android:layout_height="wrap_content" android:layout_width="fill_parent" android:layout_weight="10"> <Button android:id="@+id/Button02" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="top|center" android:text="Button2" android:onClick="onClickButton02" android:width="150dp" android:height="150dp"></Button> <ImageView android:id="@+id/ImageView01" android:layout_width="wrap_content" android:layout_height="wrap_content"></ImageView> </FrameLayout> <LinearLayout android:orientation="vertical" android:id="@+id/layout" android:layout_weight="1" android:layout_height="wrap_content" android:layout_width="fill_parent"> <Button android:id="@+id/Button01" android:layout_height="wrap_content" android:text="Show" android:layout_width="fill_parent" android:onClick="onClickShowButton"></Button> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/TextViewPoint" android:text="x: y:"></TextView> </LinearLayout> </LinearLayout>
■sample.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" > <rotate android:fromDegrees="0" android:toDegrees="360" android:toYScale="0.0" android:pivotX="50%" android:pivotY="50%" android:duration="400" android:fillBefore="false" android:fillAfter="false" /> </set>
■main.java
package com.dd.sample; import android.app.Activity; import android.content.Intent; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Point; import android.graphics.Rect; import android.os.Bundle; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.animation.Animation.AnimationListener; import android.widget.Button; import android.widget.ImageView; public class DragAndDropSample extends Activity implements OnTouchListener { ImageView target; private Animation anime; int startX; int startY; int currentX; int currentY; int offsetX; int offsetY; private Rect rect = new Rect(); private Button bt2; private boolean isBt2Click; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Resources r = getResources(); bt2 = (Button) findViewById(R.id.Button02); Bitmap bmp = BitmapFactory.decodeResource(r, R.drawable.android); anime = AnimationUtils.loadAnimation(this, R.anim.sample); anime.setAnimationListener(new AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationRepeat(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { if (isBt2Click) { bt2.performClick(); isBt2Click = false; } } }); target = (ImageView) findViewById(R.id.ImageView01); target.setImageBitmap(bmp); this.target.setOnTouchListener(this); } public void onClickShowButton(View v) { Rect rect = new Rect(); Point globalOffset = new Point(); target.getGlobalVisibleRect(rect, globalOffset); currentX = startX; currentY = startY; target.layout(currentX, currentY, currentX + target.getWidth(), currentY + target.getHeight()); target.setVisibility(View.VISIBLE); } public void onClickButton02(View v) { // Toast.makeText(this, "click", Toast.LENGTH_SHORT).show(); Intent intent = new Intent(DragAndDropSample.this, Next.class); startActivity(intent); } @Override public boolean onTouch(View v, MotionEvent event) { int x = (int) event.getRawX(); int y = (int) event.getRawY(); if (event.getAction() == MotionEvent.ACTION_MOVE) { int diffX = offsetX - x; int diffY = offsetY - y; currentX -= diffX; currentY -= diffY; target.layout(currentX, currentY, currentX + target.getWidth(), currentY + target.getHeight()); offsetX = x; offsetY = y; } else if (event.getAction() == MotionEvent.ACTION_DOWN) { offsetX = x; offsetY = y; } else if (event.getAction() == MotionEvent.ACTION_UP) { target.setAnimation(anime); target.startAnimation(anime); target.setVisibility(View.GONE); bt2.getHitRect(rect); if (rect.contains(x, y)) { isBt2Click = true; } } return true; } }