HT UI 拖拽手册

索引


概述

UI 库提供 ht.ui.DragHelper 静态类处理组件内部或者组件之间通过拖拽交换数据的需求;这个类提供的静态函数如下:

拖拽操作一般涉及的两个组件:被拖拽的组件和接受拖拽的组件;被拖拽组件和接受拖拽组件在拖拽过程中都会派发出一些事件,其中接受拖拽的组件的事件列举如下:

被拖拽组件可派发两种事件:

一个完整的拖拽流程如下:

  1. 被拖拽的组件上监听相应的原生事件,比如鼠标按下,调用 doDrag 启动拖拽
  2. 接受拖拽的组件上监听 dragEnter 事件,调用 acceptDragDrop 接受拖拽
  3. 接受拖拽的组件上监听 dragCompleted 事件,处理拖拽数据

示例

接下来我们看一个例子,页面里两个 VBoxLayout,左侧容器中有十个按钮,右侧容器是空的,拖拽 API 允许用户将左侧容器中的按钮拖拽到右侧容器中:

首先在左侧容器上监听鼠标按下事件,启动拖拽

// 按下鼠标时, 启动子组件的拖拽
vBox1.on('d:mousedown', startDrag);

function startDrag(e) {
    var view = ht.Default.getViewAt(e);
    if (view instanceof ht.ui.Button) {
        // 启动拖拽,调用 toImage 生成拖拽图片
        // 如果不想自己创建图片,可以用简单的方式:view.getRootCanvas(),因为大部分组件的内容都是直接绘制在 
        // canvas 上的,所以把 canvas 当作图片交给 DragHelper 也是可以的
        DragHelper.doDrag(view, {}, toImage(view, view.getText()), -view.getWidth() / 2, -view.getHeight() / 2);
    }
}

在右侧容器上监听拖拽相关事件:

function handleDragEvents(e) {
    if (e.kind === 'dragEnter') {
        var target = e.target;
        // 接受拖拽数据
        if (target instanceof ht.ui.VBoxLayout)
            DragHelper.acceptDragDrop(target);
    }
    else if (e.kind === 'dragMove') {
        // 计算鼠标所在的插入位置,并且在容器上绘制插入提示线
        var targetView = e.target;
        delete targetView._insertPosition;
        delete targetView._hintRect;

        var point = targetView.getContentPoint(e.nativeEvent);
        var children = targetView.getChildren();
        var childrenSize = children.size();
        for (var i = childrenSize - 1; i > -1; i--) {
            var child = children.get(i);
            if (point.y > child.getY() + child.getHeight()) {
                targetView._hintRect = {
                    x: 5,
                    y: child.getY() + child.getHeight() + targetView.getContentTop() + 2,
                    width: targetView.getWidth() - 10,
                    height: 2
                };
                targetView._insertPosition = i + 1;
                break;
            }
        }
        if (!targetView._hintRect) {
            targetView._hintRect = {
                x: 5,
                y: targetView.getContentTop() + 2,
                width: targetView.getWidth() - 10,
                height: 2
            };
            targetView._insertPosition = 0;
        }
        targetView.iv();
    }
    else if (e.kind === 'dragCompleted') {
        // 拖拽结束,处理拖拽数据
        var source = e.source,
            target = e.target;
        if (source !== target) {
            target.addView(source, {
                marginTop: 5,
                marginLeft: 5,
                marginRight: 5,
                width: 'match_parent',
                height: 'wrap_content'
            }, target._insertPosition);

            delete target._hintRect;
            delete target._insertPosition;
        }
    }
    else if (e.kind === 'dragExit' || e.kind === 'dragCanceled') {
        // 拖拽取消或鼠标移出组件范围时清空状态
        var target = e.target;
        delete target._hintRect;
        delete target._insertPosition;
        target.iv();
    }
}

欢迎交流 service@hightopo.com