Как я могу «отменить» перетаскивание во Flex? - PullRequest
5 голосов
/ 14 августа 2008

Как только я позвонил DragManager.acceptDrag, есть ли способ "отменить" перетаскивание? Скажите, что у меня есть представление, которое может принимать перетаскивание, но только в определенных областях. Когда пользователь перетаскивает одну из этих областей, я вызываю DragManager.acceptDrag(this) (из обработчика DragEvent.DRAG_OVER), но если пользователь затем выходит из этой области, я хотел бы изменить состояние перетаскивания на непринятое и показать DragManager.NONE обратная связь. Однако ни DragManager.acceptDrag(null), ни DragManager.showFeedback(DragManager.NONE), похоже, не имеют никакого эффекта. Как только я принял перетаскивание, установил тип обратной связи, я не могу изменить его.

Просто чтобы прояснить: области, в которые пользователь должен иметь возможность перетаскивать, не являются компонентами или даже отображаемыми объектами, на самом деле это просто диапазоны в тексте текстового поля (например, выделения). Если бы они были их компонентами, я бы решил это, заставив каждого из них принимать события перетаскивания индивидуально. Я думаю, я мог бы создать прокси-компоненты, которые плавают по тексту, чтобы эмулировать его, но я бы предпочел не делать этого, если это не нужно.


Теперь мне удалось заставить его работать как в AIR, так и в браузере, но только поместив прокси-компоненты поверх тех диапазонов текста, в которые вы могли бы уронить объекты. Таким образом, я получаю правильную обратную связь, и при выходе из режима перетаскивания автоматически не принимаются.

Это самая странная вещь о D & D в AIR:

DragManager.doDrag(initiator, source, event, dragImage, offsetX, offsetY);

В Flex на основе браузера offsetX и offsetY должны быть отрицательными (так говорится в документации, и она отлично работает). Однако при запуске точно такого же кода в AIR вы должны сделать смещения положительными. Те же цифры, но положительные. Это очень, очень странно.


Я протестировал еще кое-что, и что @ maclema работает, но не в том случае, если вы работаете в AIR. Кажется, что перетаскивание в AIR отличается. Это действительно очень странно, потому что обратная связь не только не отображается правильно, и от нее невозможно отказаться, но и координаты также полностью отключены. Я только что попробовал свое приложение в браузере вместо AIR, и перетаскивание полностью прервано.

Кроме того, пропуск обработчика dragEnter прекрасно работает в AIR, но нарушает все при работе в браузере.

Ответы [ 5 ]

6 голосов
/ 14 августа 2008

Вы используете только метод dragEnter? Если вы пытаетесь отклонить перетаскивание, продолжая перетаскивать один и тот же компонент, вам необходимо использовать оба метода dragEnter и dragOver.

Проверьте этот пример:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
    <mx:Script>
        <![CDATA[
            import mx.core.DragSource;
            import mx.managers.DragManager;
            import mx.events.DragEvent;

            private function onDragEnter(e:DragEvent):void {
                if ( e.target == lbl ) {

                    if ( e.localX < lbl.width/2 ) {
                        trace("accept");
                        DragManager.acceptDragDrop(this);
                    }
                    else {
                        DragManager.acceptDragDrop(null);
                    }
                }
            }

            private function doStartDrag(e:MouseEvent):void {
                if ( e.buttonDown ) {
                    var ds:DragSource = new DragSource();
                    ds.addData("test", "text");

                    DragManager.doDrag(btn, ds, e);
                }
            }
        ]]>
    </mx:Script>
    <mx:Label id="lbl" text="hello world!" left="10" top="10" dragEnter="onDragEnter(event)" dragOver="onDragEnter(event)" />
    <mx:Button id="btn" x="47" y="255" label="Button" mouseMove="doStartDrag(event)"/>
</mx:Application>
1 голос
/ 21 февраля 2013

Вы неправильно поняли концепцию. Ваше «непринятие» достигается путем реализации dragOverHandler и сигнализирования о том, что данные не нужны.

Вот основная концепция:

  1. зарегистрировать dragEnterHandler или переопределить уже зарегистрированный метод.

    function dragEnterHandler(event: DragEvent):void {
        if (data suites at least one location in this component)
            DragManager.acceptDragDrop(this);
    }
    

    Это позволяет вашему контейнеру получать дальнейшие сообщения (dragOver / dragExit). Но это НЕ место, чтобы решить, какой тип курсора мыши должен отображаться.

    Без DragManager.acceptDragDrop (this); другие обработчики не вызываются.

  2. зарегистрировать dragOverHandler или переопределить уже зарегистрированный метод.

    function dragOverHandler(event: DragEvent):void {
        if (data suites at least no location in this component) {
            DragManager.showFeedback(DragManager.NONE);
            return;
        }
    
        ... // handle other cases and show the cursor / icon you want
    }
    

    Вызов DragManager.showFeedback (DragManager.NONE); делает трюк для отображения "unaccept".

  3. зарегистрировать dragExitHandler или переопределить уже зарегистрированный метод.

    function dragOverHandler(event: DragEvent):void {
        // handle the recieved data as you like.
    }
    
1 голос
/ 18 сентября 2008

Если вам не нужны встроенные функции перетаскивания в AIR, вы можете получить поведение перетаскивания Flex, создав подкласс WindowedApplication и установив DragManager. См. Этот пост на Adobe Jira для получения дополнительной информации: https://bugs.adobe.com/jira/browse/SDK-13983

0 голосов
/ 19 августа 2008

Да, перетаскивание отличается в AIR. Я ненавижу это! Требуется много усилий, чтобы понять, как заставить вещи работать так же, как и в обычном dnd, встроенном в flex.

Что касается координат, возможно, поиграйтесь с методами localToContent и localToGlobal. Они могут помочь в переводе координат на что-то полезное.

Удачи. Я дам вам знать, если что-нибудь еще подумаю.

0 голосов
/ 15 августа 2008

хорошо, теперь я вижу проблему. Вместо нуля попробуйте установить его в dragInitiator.

Проверьте это.

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
    <mx:Script>
        <![CDATA[
            import mx.controls.Alert;
            import mx.events.DragEvent;
            import mx.managers.DragManager;
            import mx.core.DragSource;

            private function doStartDrag(e:MouseEvent):void {
                if ( e.buttonDown && !DragManager.isDragging ) {
                var ds:DragSource = new DragSource();
                ds.addData("test", "test");

                DragManager.doDrag(btn, ds, e);
                }
            }

            private function handleDragOver(e:DragEvent):void {
                if ( e.localX < cvs.width/2 ) {
                    //since null does nothing, lets just set to accept the drag
                    //operation, but accept it to the dragInitiator
                    DragManager.acceptDragDrop(e.dragInitiator);
                }   
                else {
                    //accept drag
                    DragManager.acceptDragDrop(cvs);
                    DragManager.showFeedback( DragManager.COPY );
                }
            }

            private function handleDragDrop(e:DragEvent):void {
                if ( e.dragSource.hasFormat("test") ) {
                    Alert.show("Got a drag drop!");
                }
            }
        ]]>
    </mx:Script>
    <mx:Canvas x="265" y="66" width="321" height="245" backgroundColor="#FF0000" id="cvs" dragOver="handleDragOver(event)" dragDrop="handleDragDrop(event)">
    </mx:Canvas>
    <mx:Button id="btn" x="82" y="140" label="Drag Me" mouseDown="doStartDrag(event)"/>
</mx:WindowedApplication>
...