检索Android View的精确放置位置

时间:2013-05-09 13:32:56

标签: android drag-and-drop

目标应用程序允许用户拖放视图以在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;
    }
}

我想在下拉操作中检索&#34; finger&#34;的初始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);

0 个答案:

没有答案