拖动视图时设置自定义锚点

10

我正在使用Android的Drag&Drop API,并尝试将拖影的锚点设置为在View中触摸的点。默认情况下,锚点位于View的中心。

我做了一些研究,似乎可以通过覆盖DragShadowBuilder类中的onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint)方法来完成此操作。据我所理解,如果我更改shadowTouchPoint的x、y坐标,它应该会修改拖动锚点的坐标。

我所做的是扩展DragShadowBuilder类,如下所示:

class EventDragShadowBuilder extends DragShadowBuilder {

    int touchPointXCoord, touchPointYCoord;

    public EventDragShadowBuilder() {
        super();
    }

    public EventDragShadowBuilder(View view, int touchPointXCoord,
            int touchPointYCoord) {

        super(view);
        this.touchPointXCoord = touchPointXCoord;
        this.touchPointYCoord = touchPointYCoord;
    }

    @Override
    public void onProvideShadowMetrics(Point shadowSize,
            Point shadowTouchPoint) {

        shadowTouchPoint.set(touchPointXCoord, touchPointYCoord);

        super.onProvideShadowMetrics(shadowSize, shadowTouchPoint);
    }
}

在使用拖放的Fragment中,我创建了两个监听器来启动一个View的拖动事件:
mEventLongClickListener = new OnLongClickListener() {

    @Override
    public boolean onLongClick(View view) {

        EventDragShadowBuilder shadowBuilder = new EventDragShadowBuilder(
            view, mEventTouchXCoord, mEventTouchYCoord);

        view.startDrag(null, shadowBuilder, view, 0);

        return true;
    }
};

// We need this listener in order to get the corect coordinates for the
// drag shadow
mEventTouchListener = new OnTouchListener() {

    @Override
    public boolean onTouch(View view, MotionEvent event) {

        final int action = event.getAction();

        switch (action & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN: {
            mEventTouchXCoord = (int) event.getX();
            mEventTouchYCoord = (int) event.getY();
            break;
        }
        }
        return false;
    }
};

我设定了两个监听器:

itemView.setOnLongClickListener(mEventLongClickListener);
itemView.setOnTouchListener(mEventTouchListener);

到目前为止一切都好。但当我测试应用程序并开始拖动过程时,拖影位于触摸点下方的中心位置。所以它使用了默认行为。我尝试进行调试,并且看到 mEventTouchXCoordmEventTouchYCoord 被正确地设置了。方法 shadowTouchPoint.set(touchPointXCoord, touchPointYCoord); 获取了正确的坐标,但仍然将其居中。

我不知道我做错了什么。也许我误解了API。任何帮助或提示都将不胜感激。

2个回答

12

好的,就像Scoup所说,问题出在onProvideShadowMetrics()方法中。事实是,如果我删除超级构造函数super.onProvideShadowMetrics(shadowSize, shadowTouchPoint);,它将不再显示拖动阴影。

仔细查看API方法,我发现了这个:

public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) {
    final View view = mView.get();
    if (view != null) {
        shadowSize.set(view.getWidth(), view.getHeight());
        shadowTouchPoint.set(shadowSize.x / 2, shadowSize.y / 2);
    } else {
        Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view");
    }
}

确实,它将 shadowTouchPoint 重置为拖动的 View 中心。但它也会将拖动阴影初始化到正确的尺寸。虽然我想要拖动阴影的尺寸正确设置,但我不想重置 shadowTouchPoint

最简单的方法是在使用自定义值初始化 shadowTouchPoint 之前调用超级构造函数 如下所示:

@Override
public void onProvideShadowMetrics(Point shadowSize,
    Point shadowTouchPoint) {

    super.onProvideShadowMetrics(shadowSize, shadowTouchPoint);

    shadowTouchPoint.set(touchPointXCoord, touchPointYCoord);    
}

另一个解决方案是自己处理拖动阴影View,完全跳过超类构造函数。我会提供详细更新。


9
我想问题出在这行代码:super.onProvideShadowMetrics(shadowSize, shadowTouchPoint); 你已经在这里更改了shadowTouchPoint.set(touchPointXCoord, touchPointYCoord)的值,但当调用super时,你传递的是被"super"默认方法替换的shadowTouchPoint。默认行为是将shadowTouchPoint居中。
因此,只需删除此行即可。

谢谢你的回答。虽然它没有解决我的问题,但是你让我找到了正确的方向。为此点赞+1。 - Bandreid
经过一番考虑,我决定给予您奖赏,因为您的回答确实帮助我解决了问题 :) - Bandreid
谢谢。我很高兴能够帮助! - Scoup

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接