ドラッグ移動させた画像のZオーダーで、位置が戻るo(*≧д≦)o

369 views
Skip to first unread message

nori nihonandroidnokai

unread,
Apr 30, 2015, 3:02:36 AM4/30/15
to android-g...@googlegroups.com
いつもお世話になっております。

複数の画像があって、ドラッグして移動させるアプリを作っています。
たとえば、カードゲームのUNOみたいなかんじで、
カードを積んだ山から1枚ずつ手元に寄せて…みたいなことをしたいのです。

ところが、

カードの山の1枚目(X)を移動させ終えた(ドロップし終えた)あとに、
またカードの山からカード(Y)を移動させようとドロップすると、
Xが 初期の位置 に戻ってしまうんです(移動した所に留まってくれない)。

この現象は、4.3端末までなら移動した所に留まってくれるんですが、
4.4端末からは、移動した所に留まってくれないんです。

--------------------▼レイアウトXML▼
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">

  <ImageView
    android:id="@+id/view1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center" 
    android:background="@drawable/red_card_0"/>
  <ImageView
    android:id="@+id/view2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center" 
    android:background="@drawable/red_card_1"/>

</FrameLayout>
--------------------▲レイアウトXML▲

FrameLayoutを使っていますが、ルートをRelativeLayoutにしても
同じ現象がおきました。

--------------------▼Activityクラス▼
public class MoveActivity extends Activity implements OnTouchListener {
  private View move_view1;
  private View move_view2;
    
  int currentX;   //Viewの左辺座標:X軸
  int currentY;   //Viewの上辺座標:Y軸
  int offsetX;  //画面タッチ位置の座標:X軸
  int offsetY;  //画面タッチ位置の座標:Y軸
   
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    move_view1 = findViewById(R.id.view1);
    move_view2 = findViewById(R.id.view2);

    //リスナーの設定
    move_view1.setOnTouchListener(this);
    move_view2.setOnTouchListener(this);
  }

  @Override
  public boolean onTouch(View view, MotionEvent event) {
    int x = (int) event.getRawX();
    int y = (int) event.getRawY();

    switch(event.getAction()) {
    case MotionEvent.ACTION_MOVE:
      int diffX = offsetX - x;
      int diffY = offsetY - y;

      currentX -= diffX;
      currentY -= diffY;
      view.layout(currentX, currentY, currentX + view.getWidth(), currentY + view.getHeight());
      offsetX = x;
      offsetY = y;
    break;
    case MotionEvent.ACTION_DOWN:
    view.bringToFront(); // ※どうしても最前面に出したい
    currentX = view.getLeft();
      currentY = view.getTop();
      offsetX = x;
      offsetY = y;
      break;
    case MotionEvent.ACTION_UP:
      break;
    }

    return true;
  }
}
--------------------▲Activityクラス▲

ポイントは、※印のView#bringToFrontで、
この行をコメントアウトすれば、"初期の位置に戻ってしまう"ということはなくなります。
が、私は、どうしても、
ドラッグ移動させた画像を 最前面に出したい(Zオーダーしたい) のです。

自分なりにソースを調べてみると、
View#bringToFrontは、結局、親View(この場合FrameLayoutイコールViewGroup)の
bringChildToFront(this)を呼び出しているのですが、

--------------------▽API18までのViewGroup#bringChildToFront▽
public void bringChildToFront(View child) {
  int index = indexOfChild(child);
  if (index >= 0) {
    removeFromArray(index);
    addInArray(child, mChildrenCount);
    child.mParent = this;
  }
}
--------------------△API18までのViewGroup#bringChildToFront△

に、対して、KitKatからのViewGroup.javaは、

--------------------▽API19からのViewGroup#bringChildToFront▽
public void bringChildToFront(View child) {
  int index = indexOfChild(child);
  if (index >= 0) {
    removeFromArray(index);
    addInArray(child, mChildrenCount);
    child.mParent = this;
    requestLayout(); // ←これと!
    invalidate(); // ←これ!
  }
}
--------------------△API19からのViewGroup#bringChildToFront△

と、2行追記の実装変更がされてありました。

にも、
Prior to KITKAT this method should be followed by calls to requestLayout() and invalidate() on the view's parent to force the parent to redraw with the new child ordering.
と書かれてあります。

なんとか、『ドラッグ移動した画像を最前面にさせつつ、その場に留まって欲しい』
のですが、どなたかご教授いただければと存じます。

なにとぞよろしくお願いいたします。

Makoto Yamazaki

unread,
Apr 30, 2015, 3:12:35 AM4/30/15
to android-g...@googlegroups.com
zaki です。

ドラッグ中は View の translateX, translateY で見かけ上の位置を変更し、
ACTION_UP の際に移動させたい View の LayoutParam を更新して位置を
変えるようにするのが一般的な実装方法ではないかと思います。

--
このメールは Google グループのグループ「日本Androidの会」に登録しているユーザーに送られています。
このグループから退会し、グループからのメールの配信を停止するには android-group-j...@googlegroups.com にメールを送信してください。
このグループに投稿するには android-g...@googlegroups.com にメールを送信してください。
http://groups.google.com/group/android-group-japan からこのグループにアクセスしてください。
その他のオプションについては https://groups.google.com/d/optout にアクセスしてください。



--
YAMAZAKI Makoto
Reply all
Reply to author
Forward
0 new messages