拖放 Drag and drop

Posted xhBruce

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了拖放 Drag and drop相关的知识,希望对你有一定的参考价值。

拖放 Drag and drop

android11-release
Android Developers > Docs > Guides Drag and drop
Android 开发者 > 文档 > 指南 拖放


View.OnDragListener

实现 View.OnDragListener 的拖动事件监听器或其 onDragEvent(DragEvent) 回调方法来接收拖动事件

拖放过程中四种状态:开始继续放下结束

Drag and drop 监听拖拽事件DragEvent 操作类型:

getAction() 值含义
ACTION_DRAG_STARTED当应用调用 startDrag() 并获取拖动阴影后,视图对象的拖动事件监听器会立即收到此事件操作类型。
ACTION_DRAG_ENTERED当拖动阴影刚进入视图的边界框时,视图对象的拖动事件监听器会收到此事件操作类型。这是监听器在拖动阴影进入边界框时收到的第一个事件操作类型。如果监听器想继续接收此操作的拖动事件,必须向系统返回布尔值 true
ACTION_DRAG_LOCATION当收到 ACTION_DRAG_ENTERED 事件且拖动阴影仍在视图的边界框内时,该视图对象的拖动事件监听器会收到此事件操作类型。
ACTION_DRAG_EXITED当收到 ACTION_DRAG_ENTERED 和至少一个 ACTION_DRAG_LOCATION 事件,并且用户已将拖动阴影移至视图的边界框以外时,该视图对象的拖动事件监听器会收到此事件操作类型。
ACTION_DROP当用户将拖动阴影释放到视图对象上时,该视图对象的拖动事件监听器会收到此事件操作类型。仅当视图对象的监听器在响应 ACTION_DRAG_STARTED 拖动事件时返回布尔值 true 时,系统才会将该操作类型发送至该监听器。如果用户将拖动阴影释放到未注册监听器的视图上或不属于当前布局的任何视图上,系统都不会发送此操作类型。

如果成功处理了放下操作,监听器应返回布尔值 true。否则,它应返回 false
ACTION_DRAG_ENDED当系统结束拖动操作时,视图对象的拖动事件监听器会收到此事件操作类型。此操作类型不一定在 ACTION_DROP 事件之后。如果系统已发送 ACTION_DROP,收到 ACTION_DRAG_ENDED 操作类型并不表示放下操作成功。监听器必须调用 getResult() 才能获得响应 ACTION_DROP 时所返回的值。如果未发送 ACTION_DROP 事件,getResult() 将返回 false

Drag and drop 监听拖拽事件DragEvent 有效数据:

getAction() 值getClipDescription() 值getLocalState() 值getX() 值getY() 值getClipData() 值
ACTION_DRAG_STARTEDXXX
ACTION_DRAG_ENTEREDXXXX
ACTION_DRAG_LOCATIONXXXX
ACTION_DRAG_EXITEDXX
ACTION_DROPXXXXX
ACTION_DRAG_ENDEDXX
getAction()、describeContents()、writeToParcel() 和 toString() 方法始终返回有效数据。
如果某个方法不包含特定操作类型的有效数据,则根据其结果类型,该方法将返回 null 或 0。

拖动阴影

View.DragShadowBuilder 对象声明的方法来创建拖动阴影,然后在使用 startDrag() 开始拖动时将其传递给系统。
作为对 startDrag() 响应的一部分,系统会通过调用您在 View.DragShadowBuilder 中定义的回调方法来获取拖动阴影。

View.DragShadowBuilder 类有两个构造函数:

View.DragShadowBuilder(View)View.DragShadowBuilder()
此构造函数可接受应用的任何 View 对象。该构造函数在 View.DragShadowBuilder 对象中存储视图对象,因此在回调期间,您可以在构造拖动阴影时访问该对象。它不一定必须与用户选择开始拖动操作的视图(如有)相关联。
如果您使用此构造函数,则无需扩展 View.DragShadowBuilder 或替换其方法。默认情况下,您获取的拖动阴影与您作为参数传递的视图具有相同外观,并且中心点位于用户轻触屏幕的位置。
如果您使用此构造函数,View.DragShadowBuilder 对象中没有任何可用的视图对象(该字段被设置为 null)。如果您使用此构造函数,并且不扩展 View.DragShadowBuilder 或替换其方法,您将会获得不可见的拖动阴影。系统不会显示错误。

View.DragShadowBuilder 类有两个方法:

onProvideShadowMetrics()onDrawShadow()
当您调用 startDrag() 后,系统立即调用此方法。此方法用于向系统发送拖动阴影的尺寸和接触点。此方法有两个参数:
dimensions
一个 Point 对象。拖动阴影的宽度存储在 x 中,高度存储在 y 中。
touch_point
一个 Point 对象。接触点是在拖动操作期间,拖动阴影内应该处于用户手指下方的位置。其 X 位置存储在 x 中,Y 位置存储在 y 中。
调用 onProvideShadowMetrics() 之后,系统会立即调用 onDrawShadow() 以获取拖动阴影本身。该方法只有一个参数,即系统根据您在 onProvideShadowMetrics() 中提供的参数构建的 Canvas 对象。此方法用于在提供的 Canvas 对象中绘制拖动阴影。

XhDragSampler示例

Drag and drop官网都有详细使用说明:Android 开发者 > 文档 > 指南 拖放

长按监听进入拖拽

  • startDragAndDrop API level 24(startDrag API level 11) 进入拖拽
  • ClipData 拖放操作传输的数据的对象
  • View.DragShadowBuilder 拖动阴影
imageView.setOnLongClickListener((View.OnLongClickListener) v -> {
    ClipData.Item item = new ClipData.Item((CharSequence) v.getTag());
    ClipData dragData = new ClipData(
            (CharSequence) v.getTag(),
            new String[]{ClipDescription.MIMETYPE_TEXT_PLAIN},
            item);

    //View.DragShadowBuilder myShadow = new MyDragShadowBuilder(imageView);
    View.DragShadowBuilder myShadow = new View.DragShadowBuilder(imageView);
    // Starts the drag
    v.startDragAndDrop(dragData,       // the data to be dragged
            myShadow,           // the drag shadow builder
            null,   // no need to use local data
            0             // flags (not currently used, set to 0)
    );

    return true;
});

View.OnDragListener监听

  • 设置View.OnDragListener监听imageView.setOnDragListener(this);
  • event.getAction()都有相应的说明,ACTION_DRAG_STARTED`ACTION_DRAG_ENDED`处理开始和结束,其他action并不是非得触发或有什么选后循序,如下面日志输出
    @Override
    public boolean onDrag(View v, DragEvent event) {
        final int action = event.getAction();

        switch (action) {
            case DragEvent.ACTION_DRAG_STARTED:
                Log.d(TAG, "DragEvent.ACTION_DRAG_STARTED = " + DragEvent.ACTION_DRAG_STARTED);
                return true;
                
            case DragEvent.ACTION_DRAG_ENTERED:
                Log.d(TAG, "DragEvent.ACTION_DRAG_ENTERED = " + DragEvent.ACTION_DRAG_ENTERED);
                return true;

            case DragEvent.ACTION_DRAG_LOCATION:
                Log.d(TAG, "DragEvent.ACTION_DRAG_LOCATION = " + DragEvent.ACTION_DRAG_LOCATION);
                return true;

            case DragEvent.ACTION_DRAG_EXITED:
                Log.d(TAG, "DragEvent.ACTION_DRAG_EXITED = " + DragEvent.ACTION_DRAG_EXITED);
                return true;

            case DragEvent.ACTION_DROP:
                Log.d(TAG, "DragEvent.ACTION_DROP = " + DragEvent.ACTION_DROP);
                return true;

            case DragEvent.ACTION_DRAG_ENDED:
                Log.d(TAG, "DragEvent.ACTION_DRAG_ENDED = " + DragEvent.ACTION_DRAG_ENDED);

                if (event.getResult()) {
                    Toast.makeText(this, "The drop was handled.", Toast.LENGTH_LONG).show();

                } else {
                    Toast.makeText(this, "The drop didn't work.", Toast.LENGTH_LONG).show();

                }
                return true;

            default:
                Log.e(TAG, "Unknown action type received by OnDragListener.");
                break;
        }
        return false;
    }


以上是关于拖放 Drag and drop的主要内容,如果未能解决你的问题,请参考以下文章

PYQT5 (十八)文件拖放(drag and drop)并获取文件信息

delphi Drag and Drop sample 鼠标拖放操作实例

原生拖拽,拖放事件(drag and drop)

r 拖放闪亮的文件上传 - http://stackoverflow.com/questions/36108705/drag-and-drop-data-into-shiny-app

拖放网站生成器javascript库。

Swift Drag and Drop 不能在 Xcode 之外工作