Получение точной позиции перетаскивания Android View

Целевое приложение позволяет пользователю перетаскивать или перетаскивать представления, чтобы переместить их в FrameLayout или сохранить их в другом LinearLayout.

Общий механизм работает, но я не могу получить нужную точность в позиции, когда вид снижается, он «скачет» немного дальше. Как я мог получить позицию теневой тени, чтобы поместить упавшее представление точно там, где была тень, чтобы избежать какого-либо артефакта «прыгать»?

Для примера макет довольно прост, вот обзор с двумя объектами TextView, которые можно перемещать (я удалил все детали):

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"> <LinearLayout android:id="@+id/repository"/> <FrameLayout android:id="@+id/frame"> <TextView android:id="@+id/view1"/> <TextView android:id="@+id/view2"/> </FrameLayout> </LinearLayout> 

Во-первых, чтобы улучшить начальную позицию самой теневой тени, я переопределяю onProvideShadowMetrics . Благодаря этому представление не перескакивает, когда пользователь начинает его перетаскивать:

 private class MyDragShadowBuilder extends View.DragShadowBuilder { private float x, y; public MyDragShadowBuilder(View view, float x, float y) { super(view); this.x = x; this.y = y; } @Override public void onProvideShadowMetrics(Point size, Point touchPoint) { super.onProvideShadowMetrics(size, touchPoint); touchPoint.set((int) x, (int) y); } } 

Затем для запуска операции перетаскивания используется реализация OnTouchListener :

 private class LongClickListener implements View.OnTouchListener { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { TextView tv = (TextView) v; if (tv != null) { ClipData data = ClipData.newPlainText("", ""); MyDragShadowBuilder shadowBuilder = new MyDragShadowBuilder(v, event.getX(), event.getY()); v.startDrag(data, shadowBuilder, v, 0); v.setVisibility(View.INVISIBLE); return true; } } return false; } } 

Операция drop – это то, где я хотел бы получить начальную позицию x, y «пальца» в представлении, чтобы позиционировать представление точно так же, как тень.

 private class DragListener implements View.OnDragListener { private final Class<?> FRAMELAYOUT_CLASS = FrameLayout.class; private final Class<?> LINEARLAYOUT_CLASS = LinearLayout.class; private Drawable enterShape = getResources().getDrawable(R.drawable.shape_droptarget); private Drawable normalShape = getResources().getDrawable(R.drawable.shape); @Override public boolean onDrag(View v, DragEvent event) { int action = event.getAction(); switch (action) { case DragEvent.ACTION_DRAG_STARTED: break; case DragEvent.ACTION_DRAG_ENTERED: v.setBackground(enterShape); break; case DragEvent.ACTION_DRAG_EXITED: v.setBackground(normalShape); break; case DragEvent.ACTION_DROP: View view = (View) event.getLocalState(); ViewGroup owner = (ViewGroup) view.getParent(); ViewGroup container = (ViewGroup) v; if (container.getClass() == FRAMELAYOUT_CLASS) { // If I could just get shadowBuilder here, I would be // able to retrieve its initial (x,y) offset // or its final (x,y) position, both work... view.setX(event.getX()); view.setY(event.getY()); } else if (container.getClass() == LINEARLAYOUT_CLASS) { // In a LinearLayout we remove any offset: view.setX(0); view.setY(0); } else return false; owner.removeView(view); container.addView(view); view.setVisibility(View.VISIBLE); break; case DragEvent.ACTION_DRAG_ENDED: v.setBackground(normalShape); default: break; } return true; } } 

Все, что установлено в методе OnCreate активности:

 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); View v = findViewById(R.id.view1); v.setOnTouchListener(new LongClickListener()); v = findViewById(R.id.view2); v.setOnTouchListener(new LongClickListener()); v = findViewById(R.id.frame); v.setOnDragListener(new DragListener()); v = findViewById(R.id.repository); v.setOnDragListener(new DragListener()); } 

Заранее благодарю за любой отзыв о том, как я должен получить эту информацию!


EDIT : Очевидно, что я мог бы передавать данные в ClipData, но это было бы неудобно (особенно, если мне нужно передавать большие массивы данных в будущем, сериализация здесь является излишним):

 ClipData data = ClipData.newPlainText( "pos", String.format("%d %d", (int)event.getX(), (int)event.getY())); v.startDrag(data, shadowBuilder, v, 0); 

 if (container.getClass() == FRAMELAYOUT_CLASS) { ClipData data = event.getClipData(); String[] pos = ((String)data.getItemAt(0).getText()).split(" "); int x = Integer.valueOf(pos[0]); int y = Integer.valueOf(pos[1]); view.setX(event.getX() - x); view.setY(event.getY() - y); 

Intereting Posts