目标应用程序允许用户拖放视图以在 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;
}
}
放置操作是我想在视图中检索“手指”的初始 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());
}
提前感谢您提供有关如何获取此信息的任何提示!
编辑:显然我可以传递 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);