[Android] ImageView をドラッグする

アイコン画像をドラッグしてごみ箱に入れるなどの、ドラッグをAndroidでやる場合にonTouchを使います。タッチした指の動きに合わせてlayoutメソッドを使い画像などを移動させ、あたかもドラッグしているようにできます。
 
imageview-drag

Android Studio 3.0.1
Android 8.0



画像をドラッグさせる

 
画像をドラッグさせるために使う仕組みは大きく以下の2つを使います

  1. layout(int, int, int, int)
    • Viewのメソッドで、上下左右の位置を変えることでViewを移動させる
  2. onTouch
    • ムーブアクションを取得してそれと同じ座標に画像を配置する

 

 

layout メソッドを使って画像を移動

 
Viewクラスのメソッドであるlayoutは、引数としてViewの left, top, right, bottom を設定できます。
 

 
View自体のサイズを固定とするとx方向、y方向の移動量と画像の縦横幅を加算することでViewを移動させられます。
 

 
これをImageViewに当てはめて画像を移動することを確認してみます。
 
MainActivity.java

 
activity_main.xml

 
リソースです
strings.xml

 

 
ボタンを押すたびに少しづつ画像が斜め下に移動していきます。
 
Buttonタップを使って画像の移動ができるようになりました。
次は画像をつかんでドラッグをタッチイベントを使って実装します。

 

onTouchでタッチイベントを拾う

 
タッチイベントを扱うものとして

があります

似たものとしては
onTouchEvent(MotionEvent motionEvent)

がありますが、これはActivityの画面全体でのタッチイベントを拾う時に使います

Activity にOnTouchListener を実装しますので

の設定が必要です

一方onTouchは例えばImageViewにリスナーを設定します

 
ところがこれはビルドエラーにはなりませんが警告が出てきます。
(このImageViewにリスナーを設定でできない事はないのですが…)
 

 
“Custom View has onTouchListner called on it but doesn’t override performClick”
performClickをoverrideしないといけないという警告です。これは簡単にはできないのでImageViewを継承したカスタムImageViewクラスを作ってoverrideします。
 

 
onTouch(View v, MotionEvent event):
Viewのタッチにより以下の状態を取得できます。

ここでタッチした位置とドラッグしていく位置を getRawX(), getRawY() で取得して
その移動量をViewにのlayoutを使って反映させることで、Viewがつかまれてドラッグされたようにしていきます。

 

サンプルコード

 
CustomImageViewクラスをImageViewを継承して作り、そのインスタンスにonTuchイベントのリスナー実装します。

MainActivity.java

 
ImageViewを継承させるのですが、android.support.v7.widget.AppCompatImageViewを使うように推奨されますのでAppCompatImageViewを継承して、念願のperformClick()をoverrideします。

CustomImageView.java

 

ConstraintLayoutは軽い?
このサンプルコードでは移動座標を TextView で表示していますが、LinearLayoutやRelativeLayoutのレイアウトを使うとTextViewを表示させないケースでは問題ないのですが、TextViewを表示や、何か別の作業をこのACTION_MOVEで行うとドラッグできなくなります。ところがConstraintLayoutを使とうまくいきます。おそらくConstraintLayoutが処理が軽いからかもしれませんね。

 
また、カスタムImageViewなので
com.example.testimageviewdrag.CustomImageView
のようにpackage name + class name で作成します。(そのままコピペしないように)

activity_main.xml

 
リソース
strings.xml

 

 

サンプル動画

 

 
logには画像をドラッグした座標が記録されています
logcat

 

関連:

References:
layout(int, int, int, int) | Android Developers
View.OnTouchListener | Android Developers
MotionEvent | Android Developers