1

如何开发像Elixir这样的 UI ,我们可以在其中选择多个对象并拖动。我们可以通过 ctrl+click 或从 selectionBox 中选择项目。

我正在使用画布并添加一些自定义组件。我想通过选择多个并拖动,选择多个并删除等来重新排列。

任何想法?

4

2 回答 2

3

在这里,我可以给你一个简单的起点。

但是,在那之前,我并没有花太多时间在这个组件上。请仅作为示例参考。你可能想写你自己的。

下面的组件使用一个额外的Canvas调用selectionLayer来进行多次拖动。当您选择一个项目时,项目将从主目录中删除Canvas并添加到selectionLayer. 如果您拖动,它会调用selectionLayer.startDrag(),以便图层中的所有内容将一起移动。当拖动完成时,它会检查图层更改的 x,y 位置(因为子组件实际上没有移动;selectionLayer确实如此)并将其应用于拖动的组件,同时移动selectionLayer到原始位置(0,0)

DraggableCanvas.as:

package 
{
    import flash.display.DisplayObject;
    import flash.events.Event;
    import flash.events.MouseEvent;

    import mx.containers.Canvas;
    import mx.core.UIComponent;

    public class DraggableCanvas extends Canvas
    {
        protected var selectionLayer:Canvas;
        protected var isDragging:Boolean;

        public function DraggableCanvas()
        {
            super();
            isDragging = false;
            addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
        }

        protected function addedToStageHandler(event:Event):void
        {
            stage.addEventListener(MouseEvent.MOUSE_DOWN, stage_mouseDownHandler);
        }

        protected function stage_mouseDownHandler(event:MouseEvent):void
        {
            if (!isChildOf(event.target as DisplayObject))
                deselectAll();
        }

        override public function addChildAt(child:DisplayObject, index:int):DisplayObject
        {
            if (child is UIComponent)
            {
                UIComponent(child).addEventListener(MouseEvent.MOUSE_DOWN, child_mouseDownHandler);
                UIComponent(child).addEventListener(MouseEvent.MOUSE_UP, child_mouseUpHandler);
            }
            return super.addChildAt(child, index);
        }

        override protected function createChildren():void
        {
            super.createChildren();
            selectionLayer = new Canvas();
            selectionLayer.percentWidth = selectionLayer.percentHeight = 100;
            selectionLayer.alpha = 0.5;
            super.addChildAt(selectionLayer, 0);
        }

        protected function child_mouseDownHandler(event:MouseEvent):void
        {
            var target:UIComponent = event.currentTarget as UIComponent;

            if (!isSelected(target))
            {
                if (!event.ctrlKey)
                    deselectExcept(target);
                select(target);
                target.addEventListener(MouseEvent.MOUSE_MOVE, child_mouseMoveHandler);
            }
            else
            {
                if (event.ctrlKey)
                    deselect(target);
                else
                    target.addEventListener(MouseEvent.MOUSE_MOVE, child_mouseMoveHandler);
            }
        }

        protected function child_mouseMoveHandler(event:MouseEvent):void
        {
            var target:UIComponent = event.currentTarget as UIComponent;

            selectionLayer.startDrag();
            isDragging = true;

            target.removeEventListener(MouseEvent.MOUSE_MOVE, child_mouseMoveHandler);
        }

        protected function child_mouseUpHandler(event:MouseEvent):void
        {
            var target:UIComponent = event.currentTarget as UIComponent;

            target.removeEventListener(MouseEvent.MOUSE_MOVE, child_mouseMoveHandler);

            if (isDragging)
            {
                if (target.parent == selectionLayer)
                {
                    selectionLayer.stopDrag();
                    isDragging = false;

                    for (var i:int = 0; i < selectionLayer.numChildren; i++)
                    {
                        var child:UIComponent = selectionLayer.getChildAt(i) as UIComponent;
                        child.move(child.x + selectionLayer.x, child.y + selectionLayer.y);
                    }

                    selectionLayer.move(0,0);
                }
            }
        }

        private function isSelected(target:DisplayObject):Boolean
        {
            return target.parent == selectionLayer;
        }

        private function isChildOf(obj:DisplayObject):Boolean
        {
            var p:DisplayObject = obj.parent;
            while (p)
            {
                if (p == this)
                    return true;
                p = p.parent;
            }
            return false;
        }

        private function select(target:DisplayObject):void
        {
            if (isSelected(target))
                return;
            super.removeChild(target);
            selectionLayer.addChild(target);
        }

        private function deselect(target:DisplayObject):void
        {
            if (!isSelected(target))
                return;
            selectionLayer.removeChild(target);
            super.addChild(target);
        }

        private function deselectExcept(target:DisplayObject):void
        {
            var children:Array = selectionLayer.getChildren();
            for each (var child:DisplayObject in children)
            {
                if (target != child)
                    deselect(child);
            }
        }

        private function deselectAll():void
        {
            deselectExcept(null);
        }
    }
}

示例应用程序:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.adobe.com/flex/spark"
               xmlns:mx="library://ns.adobe.com/flex/mx"
               xmlns="*"
               minWidth="955" minHeight="600">

    <DraggableCanvas width="100%" height="100%">
        <mx:Panel x="10" y="10"/>
        <mx:Panel x="150" y="10"/>
        <mx:Panel x="300" y="10"/>
    </DraggableCanvas>

</s:Application>

另一个建议是,由于您使用的是 Flex 4.5,因此也建议使用子类化SkinnableDataContainer或。ListBase那些带有 ItemRenderer 的组件提供了很好的功能。但如果您不熟悉火花组件,请不要介意。

于 2014-04-21T21:59:18.377 回答
1

您可以从阅读和研究一个提供 Elixir 核心功能的开源应用程序开始。该项目是ObjectHandles

于 2014-04-21T13:32:04.233 回答