【Android】Viewをタッチして移動させる

投稿者: | 2011年6月3日

Viewをタッチすると移動させることができるUIを考えてみる。
ツールボタン的なUIに活用できるかもしれない。

これを実現するためには、サンプルプログラムのように実装したOnTouchListenerを移動させたいViewへセットしておけばよい。
移動対象のViewはRelativeLayoutの子Viewとなっており、タッチイベントでLayoutParamsのtopMarginとleftMarginを書き換えている。
複数のViewに同じリスナを登録すれば、それぞれのViewごとに移動させることができる。

MainActivity.java

public class MainActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        final OnTouchListener moving = new OnTouchListener() {

        	private float downX;
        	private float downY;

        	private int downLeftMargin;
        	private int downTopMargin;

        	@Override
            public boolean onTouch(View v, MotionEvent event) {

         // ViewGroup.MarginLayoutParamsでキャストすることで
                // FrameLayoutの子要素であっても同様に扱える。
                final ViewGroup.MarginLayoutParams param = 
                    (ViewGroup.MarginLayoutParams)v.getLayoutParams();

                if( event.getAction() == MotionEvent.ACTION_DOWN ){

                    downX = event.getRawX();
                    downY = event.getRawY();

                    downLeftMargin = param.leftMargin;
                    downTopMargin = param.topMargin;

                    return true;
                }
                else if( event.getAction() == MotionEvent.ACTION_MOVE){

                    param.leftMargin = downLeftMargin + (int)(event.getRawX() - downX);
                    param.topMargin = downTopMargin + (int)(event.getRawY() - downY);

                    v.layout(
               param.leftMargin, 
               param.topMargin, 
               param.leftMargin + v.getWidth(), 
               param.topMargin + v.getHeight());

                    return true;
                }

                return false;
            }
		};

        // 別々のViewに、同じリスナをセットしておく
		findViewById(R.id.myView1).setOnTouchListener(moving);
		findViewById(R.id.myView2).setOnTouchListener(moving);
    }
}

main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
	<LinearLayout
		android:id="@+id/myView1"
	    android:layout_width="100dp"
	    android:layout_height="200dp"
	    android:background="#ffff0000"
	    android:layout_marginLeft="0dp"
	    android:layout_marginTop="0dp"
	    android:orientation="vertical">
		<TextView
			android:layout_width="fill_parent"
			android:layout_height="wrap_content"
			android:text="toolmenu" />
		<Button
			android:layout_width="fill_parent"
			android:layout_height="wrap_content"
			android:text="Button1" />
		<Button
			android:layout_width="fill_parent"
			android:layout_height="wrap_content"
			android:text="Button2" />
		<Button
			android:layout_width="fill_parent"
			android:layout_height="wrap_content"
			android:text="Button3" />
	</LinearLayout>
	<TextView
		android:id="@+id/myView2"
	    android:layout_width="100dp"
	    android:layout_height="60dp"
	    android:background="#ff0000ff"
	    android:layout_marginLeft="50dp"
	    android:layout_marginTop="0dp"
	    android:text="MyTextView" />
</RelativeLayout>

実行結果は以下のようになる。
赤いViewと青いViewをそれぞれタッチ&ムーブで移動できる。

このプログラムを始め作ったとき、37行目でrequestLayout()を使っていた。そうすると、Viewの一部が画面の外にはみ出すと中の要素が潰れてしまっていた。

その後、layout()メソッドを使えばUI要素が潰れないことが分かったのでプログラムを修正した。

ただし実用化するならば、画面外への移動は抑制させるなりの対処が必要だろう。

【Android】Viewをタッチして移動させる」への5件のフィードバック

  1. hiro99ma

    Viewを移動させるやり方がわからずに困っていたので、非常に助かりました。

    返信
    1. okazawata 投稿作成者

      コメントありがとうございました。
      これからも役立つ情報を提供できるようがんばっていきます。

      返信
  2. 横山

    Drag Dropのサンプル探しまくったのだけど、これをRelativeLayoutで
    やるという発想が素晴らしい。実は私もMargin使って自作しようとした
    矢先でこれを見つけて、助かりました。

    ありがとう。

    返信
  3. ピンバック: 【iOS】UIViewをタッチして移動させる – ザワプロ!

  4. 宮内

    試しに画像(ImageView)を動かしてみようとしたところ描画されませんでした。

    が、

    1行目のActivity → AppCompatActivityにすると描画されました。

    返信

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です