この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
以下の動きを目標にしました。
- 指にViewコンポーネント(画像)がついてくる
- 画面の右下のゴミ箱に画像をドラッグすると消える
- 一度ゴミ箱にドラッグした後、ゴミ箱をクリックしたら画面左上に画像を表示する
main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/FrameLayout01"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_weight="10"
android:background="@color/white">
<Button
android:layout_gravity="bottom|right"
android:layout_width="30dp"
android:layout_height="30dp"
android:id="@+id/trash"
android:background="@drawable/custom_button"
/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/move"
android:id="@+id/ImageView01" />
</FrameLayout>
MainActivity.java
package com.sample.movetest;
import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
public class MainActivity extends Activity
implements OnTouchListener, OnClickListener {
private FrameLayout frameLayout01;
private ImageView target;
private Button trash;
private int targetLocalX;
private int targetLocalY;
private int screenX;
private int screenY;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
frameLayout01 = (FrameLayout)findViewById(R.id.FrameLayout01);
target = (ImageView)findViewById(R.id.ImageView01);
target.setOnTouchListener(this);
trash = (Button)findViewById(R.id.trash);
trash.setOnClickListener(this);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
int x = (int)event.getRawX();
int y = (int)event.getRawY();
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
targetLocalX = target.getLeft();
targetLocalY = target.getTop();
screenX = x;
screenY = y;
break;
case MotionEvent.ACTION_MOVE:
int diffX = screenX - x;
int diffY = screenY - y;
targetLocalX -= diffX;
targetLocalY -= diffY;
target.layout(targetLocalX,
targetLocalY,
targetLocalX + target.getWidth(),
targetLocalY + target.getHeight());
screenX = x;
screenY = y;
break;
case MotionEvent.ACTION_UP:
int trashLeft = trash.getLeft() + trash.getWidth()/2;
int trashTop = trash.getTop() + trash.getHeight()/2;
int targetRight = target.getLeft() + target.getWidth();
int targetBottom = target.getTop() + target.getHeight();
if (targetRight > trashLeft && targetBottom > trashTop) {
frameLayout01.removeView(target);
}
break;
}
return true;
}
@Override
public void onClick(View v) {
int childCount = frameLayout01.getChildCount();
if(childCount == 1) {
frameLayout01.addView(target);
}
}
}
■使用するレイアウト
ゴミ箱に画像をドラッグする(重ねる)ので 使用するレイアウトは、FrameLayoutを使いました。 FrameLayoutは、複数のViewを重ねて表示することができます。 位置を何も指定しない場合は、左上に表示されます。 また、後から配置したViewが前面に配置されます。 FrameLayoutの他にRelativeLayoutもViewを重ねて表示することが できます。
■動かす対象Viewのタッチイベントを検知して処理する
MainActivity.javaの14行目
implements OnTouchListener, OnClickListener {
オブジェクトごとのタッチイベントの検知は、 OnTouchListenerインターフェースを実装します。
MainActivity.javaの33行目
target.setOnTouchListener(this);
動かす対象Viewにタッチイベントのリスナー登録をします。
MainActivity.javaの40~87行目
@Override
public boolean onTouch(View v, MotionEvent event) {
…
}
onTouchというコールバックメソッドをオーバーライドします。 Viewを指で動かした時のタッチイベントを検知したいので今回はonTouchを使います。 また、ViewごとでなくActivity全体のタッチイベントの検知は、 onTouchEvent()コールバックメソッドをオーバーライドします。
MainActivity.javaの42~43行目
int x = (int)event.getRawX();
int y = (int)event.getRawY();
タッチした場所の絶対座標を取得します。 絶対座標を取得するにはgetRawX(),getRawY()を使用しますが、 相対座標を取得する場合はgetX(),getY()を使用します。
MainActivity.javaの45~85行目
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
…
}
case MotionEvent.ACTION_DOWN: → 押したとき、 case MotionEvent.ACTION_MOVE: → 動かしたとき、 case MotionEvent.ACTION_UP: → 離したときと タッチイベントのアクションごとに処理をわけます。 アクションはDOWN→MOVE→UPの順番で発生します。 今回は使用していないですが、他には ACTION_CANCEL(タッチがキャンセルされたとき) ACTION_OUTSIDE(対象のViewの範囲外をタッチしたとき)があります。
MainActivity.javaの46~54行目
case MotionEvent.ACTION_DOWN:
targetLocalX = target.getLeft();
targetLocalY = target.getTop();
screenX = x;
screenY = y;
break;
押したときの処理
対象Viewの左端座標を親Viewの相対座標として取得し、targetLocalXに入れます。 対象Viewの上端座標を親Viewの相対座標として取得し、targetLocalYに入れます。 タッチした場所のx座標をscreenXに入れます。 タッチした場所のy座標をscreenXに入れます。
MainActivity.javaの56~72行目
case MotionEvent.ACTION_MOVE:
int diffX = screenX - x;
int diffY = screenY - y;
targetLocalX -= diffX;
targetLocalY -= diffY;
target.layout(targetLocalX,
targetLocalY,
targetLocalX + target.getWidth(),
targetLocalY + target.getHeight());
screenX = x;
screenY = y;
break;
動かしたときの処理
押したときの座標と動かしたときの座標の差分をdiffX,diffYに入れます。 targetLocalX,targetLocalYに差分を反映させます。 差分を反映させた位置に対象Viewを移動させます。 タッチした場所のx座標をscreenXに入れます。 タッチした場所のy座標をscreenXに入れます。
MainActivity.javaの74~85行目
case MotionEvent.ACTION_UP:
int trashLeft = trash.getLeft() + trash.getWidth()/2;
int trashTop = trash.getTop() + trash.getHeight()/2;
int targetRight = target.getLeft() + target.getWidth();
int targetBottom = target.getTop() + target.getHeight();
if (targetRight > trashLeft && targetBottom > trashTop) {
frameLayout01.removeView(target);
}
break;
離したときの処理
ゴミ箱に入れたと判定する為の位置座標をtrashLeft,trashTopに入れます。 対象の右端座標、下端座標がtrashLeft,trashTop超えた場合は 対象Viewを削除します。
■ゴミ箱をクリックしたときの処理
MainActivity.javaの14行目
implements OnTouchListener, OnClickListener {
クリックイベントの検知は、OnClickListenerインターフェースを実装します。
MainActivity.javaの36行目
trash.setOnClickListener(this);
ゴミ箱用のコンポーネントににクリックイベントのリスナー登録をします。
MainActivity.javaの92~94行目
if(childView == null) {
frameLayout01.addView(target);
}
動かす対象Viewが画面にない場合は、表示させます。