Android開発をする際に必ず必要となるのがレイアウトの知識です。
ですが、Androidのレイアウト表示は多少クセのある部分があります。
ということで、今回は「タップした位置にビューを移動する方法(注意点)」をお届けしたいと思います。
[最終結論] getLocationOnScreen() にはステータスバーの高さも含まれているので、setY() を使うときは注意が必要。
まず、「タップした位置にビューを移動する」というのはどういうことかというと、
このように、タッチしたビューを基準にして他のビューを移動させることです。
「今ココを選択してますよ〜」、みたいなやつですね。
では、これを実現するための順序を。
1. タッチイベントをつくる。
2. タッチされたビューの位置を取得。
3. その位置を基準にして移動させたいビューの位置を設定。
という流れです。
※ちなみにレイアウトのxml には<RelativeLayout> を使った例になります。
では、まず1番の「タッチイベントをつくる」から。
と言っても、これは簡単ですね。
該当する xml に <ImageView>を書き込んで、onCreate() の中で
ImageView imageView = (ImageView) findViewById(R.id.image_view);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// ここに2番、3番の処理を書きます。
}
});
とやればオッケーです。
では、次に2番「タッチされたビューの位置を取得」にうつりましょう。
まずタッチされたビュー(ここではR.id.image_view)の位置を取得します。
つまり、以下のようなことですね。
この部分を追加したコードは以下。
ImageView imageView = (ImageView) findViewById(R.id.image_view);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ImageView touchImageView = (ImageView) findViewById(R.id.image_view);
int[] locations = new int[2];
touchImageView.getLocationOnScreen(locations); //ここで位置が格納される。
}
});
※この例ではタッチイベントを使わない場合も考慮して findViewById を使っていますが、単純に引数のView v を使ってもOKです。ちょっと複雑な場合は無視してオッケーです。^-^
はい。
これで、タッチされたビューの「画面の左上からの」位置がlocations の中に取得できました。
ちなみに、、、
locations[0] がX軸(Left位置で使用)
locations[1] がY軸(Top位置で使用)
になります。
では、最後の3番「その位置を基準にして移動させたいビューの位置を設定」です。
まず移動させたいビューを findViewById で取得して、setX()とsetY() で位置を設定します。
この部分はのコードは、、、
ImageView imageView = (ImageView) findViewById(R.id.image_view);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ImageView touchImageView = (ImageView) findViewById(R.id.image_view);
int[] locations = new int[2];
touchImageView.getLocationOnScreen(locations); //ここで位置が格納される。
int touchedImageX = locations[0];
int touchedImageY = locations[1];
// ↓↓↓ここから移動させたいビュー の設定
ImageView moveImageView = (ImageView) findViewById(R.id.move_image_view);
moveImageView.setX(touchedImageX); //取得した位置をセット
moveImageView.setY(touchedImageY); //取得した位置をセット
}
});
これでOK。
…ではないのです!!
なぜかというと、 どうやらsetX() と setY() は最初に位置を取得した getLocationOnScreen() とは開始点が違うようなので、これだと少しずれた場所に移動させられてしまうのです。
つまり、わかりやすく言うと
画面上部にあるステータスバーが含まれていない位置を指定しなければいけないのです。
なので、ステータスバーの影響をうけないLeftの位置は問題ありませんが、
設定するべきTopの位置 = getLocationOnScreen() で取得したY座標 - ステータスバーの高さ
となります。
ステータスバーの高さは
Rect rect = new Rect();
Window window = getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rect);
int statusBarHeight = rect.top; // ステータスバーの高さ
で取得できるので、 最終的なコードは
ImageView imageView = (ImageView) findViewById(R.id.image_view);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ImageView touchImageView = (ImageView) findViewById(R.id.image_view);
int[] locations = new int[2];
touchImageView.getLocationOnScreen(locations); //ここで位置が格納される。
int touchedImageX = locations[0];
int touchedImageY = locations[1];
// ↓↓↓ここから移動させたいビュー の設定
Rect rect = new Rect();
Window window = getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rect);
int statusBarHeight = rect.top; // ステータスバーの高さ
ImageView moveImageView = (ImageView) findViewById(R.id.move_image_view);
moveImageView.setX(touchedImageX);
moveImageView.setY(touchedImageY-statusBarHeight); // ←ココ
}
});
でOKです。
ただし、これはタッチされた画像の左上の点にビューを移動させることになりますので、もしビューの真ん中だとかちょっとずらしたい場合は画像の幅をとって1/2にするなどして位置を調整する必要があります。
また、ビューをタッチした時ではなく、アプリ(アクティビティ)を起動した瞬間にこのテクニックを使う場合には以下のように onWindowFocusChanged() 内で行なってください。onCreate() では早すぎてビューの位置やサイズを取得できないようです。
@Override
public void onWindowFocusChanged(boolean hasFocus) {
// ここに追加。
}
以上になります。
お疲れ様でした。^-^
ちなみに記事中で使ってる画像は今作っているゲームアプリのサンプルです。
まだまだ時間がかかりそうです。^-^;
0 件のコメント:
コメントを投稿