如何仅在android中限制沿y轴拖放?

如何仅在android中限制沿y轴拖放?,android,drag-and-drop,Android,Drag And Drop,我试图将拖放运动限制为仅Y轴,以便用户只能查看视图并将其向上或向下拖动,而不是向左或向右拖动 我现在有两个视图(textView和dropZone的ID)。其中一个(textView)设置了触摸监听器,另一个(dropZone)设置了拖动监听器 以下是布局xml(activity_main.xml): 从上面的代码可以看出,当用户将textView拖到dropZone上时,我会尝试将dropZone视图的背景色改为蓝色。如果我在ACTION_DOWN运动事件中使用创建DragShadowBuil

我试图将拖放运动限制为仅Y轴,以便用户只能查看视图并将其向上或向下拖动,而不是向左或向右拖动

我现在有两个视图(textView和dropZone的ID)。其中一个(textView)设置了触摸监听器,另一个(dropZone)设置了拖动监听器

以下是布局xml(activity_main.xml):

从上面的代码可以看出,当用户将textView拖到dropZone上时,我会尝试将dropZone视图的背景色改为蓝色。如果我在ACTION_DOWN运动事件中使用创建DragShadowBuilder,这将很好地工作:

    ClipData data = ClipData.newPlainText("", "");
    DragShadowBuilder shadow = new View.DragShadowBuilder(v);
    v.startDrag(data, shadow, v, 0);
问题是我无法控制阴影,使其仅沿Y轴(垂直)移动

如果我取出DragShadowBuilder代码(上面的三行),并在ACTION_move motion事件中添加代码来移动拖动的视图(上面已注释掉):

然后我可以控制textView仅沿Y轴移动。不幸的是,如果没有DragShadowBuilder,我无法触发DragEvent中输入的操作以将dropZone视图变为蓝色

如果我同时保留DragShadowBuilder代码和上面的四行代码,则对于拖动,ACTION_MOVE motion事件只会触发一次;它不会继续跟随拖动


有人知道我能做什么吗?这件事我已经做了一段时间了,但运气不好。我甚至一度尝试创建一个扩展Android view类的自定义视图,但我无法重写startDrag方法,因为它被声明为final。我希望我在这方面能做得更好(

啊哈!我在任何地方都找不到这个答案(很多人都在问),所以我就是这么做的

其基本思想是使DragShadow不可见,并将Y轴移动传递给要“拖动”的视图。因此,实际上,您正在拖动DragShadow,但用户会觉得可拖动视图正在移动

draggableItem.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(final View view, MotionEvent motionEvent) {
            if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
                ClipData data = ClipData.newPlainText("", "");
                View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(new View(getApplicationContext()));
                view.startDrag(data, shadowBuilder, view, 0);
                return true;
            } else {
                return false;
            }
        }
    });

mDropZone.setOnDragListener(new View.OnDragListener() {
        @Override
        public boolean onDrag(View v, DragEvent event) {
                switch (event.getAction()) {
                case DragEvent.ACTION_DRAG_STARTED:
                    ViewGroup.MarginLayoutParams lParams = (ViewGroup.MarginLayoutParams) arcMenu.getLayoutParams();
                    _yDelta = (int) event.getY() - lParams.topMargin;
                    break;
                case DragEvent.ACTION_DRAG_LOCATION:
                    ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) arcMenu.getLayoutParams();
                    layoutParams.topMargin = (int) event.getY() - _yDelta;
                    arcMenu.setLayoutParams(layoutParams);
                    break;
                case DragEvent.ACTION_DROP:
                    // Dropped, reassign View to ViewGroup
                    View view = (View) event.getLocalState();

                    // Do your drop actions here

                    view.setVisibility(View.VISIBLE);
                    break;
                default:
                    break;
            }
            return true;
        }
    });
您还需要在类中声明\u yDelta变量


希望这适用于所有酷炫的猫咪!

以下代码使拖动阴影不可见,但仍保持视图可见:

View transparentView  = new FrameLayout(getContext());
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(transparentView);
view.startDrag(data, shadowBuilder, view, 0);
可以相应地从拖动事件更改视图的y值:

view.setY(event.getY());

我喜欢移动自己的视图而不是DragShow。不过,你找到其他解决方案了吗?上面的答案中的
arcMenu
是什么?啊,这是很久以前的事了,但我认为
arcMenu
应该是
DragableItem
,我只是在一个地方重命名了它,而在其他地方忘记了。
draggableItem.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(final View view, MotionEvent motionEvent) {
            if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
                ClipData data = ClipData.newPlainText("", "");
                View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(new View(getApplicationContext()));
                view.startDrag(data, shadowBuilder, view, 0);
                return true;
            } else {
                return false;
            }
        }
    });

mDropZone.setOnDragListener(new View.OnDragListener() {
        @Override
        public boolean onDrag(View v, DragEvent event) {
                switch (event.getAction()) {
                case DragEvent.ACTION_DRAG_STARTED:
                    ViewGroup.MarginLayoutParams lParams = (ViewGroup.MarginLayoutParams) arcMenu.getLayoutParams();
                    _yDelta = (int) event.getY() - lParams.topMargin;
                    break;
                case DragEvent.ACTION_DRAG_LOCATION:
                    ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) arcMenu.getLayoutParams();
                    layoutParams.topMargin = (int) event.getY() - _yDelta;
                    arcMenu.setLayoutParams(layoutParams);
                    break;
                case DragEvent.ACTION_DROP:
                    // Dropped, reassign View to ViewGroup
                    View view = (View) event.getLocalState();

                    // Do your drop actions here

                    view.setVisibility(View.VISIBLE);
                    break;
                default:
                    break;
            }
            return true;
        }
    });
View transparentView  = new FrameLayout(getContext());
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(transparentView);
view.startDrag(data, shadowBuilder, view, 0);
view.setY(event.getY());