Flex 4: Drag-and-drop

Technika drag-and-drop (česky „táhni-a-pusť“ nebo „přetahování“) patří k užitečným prvkům, které mohou zvýšit použitelnost vaší aplikace a zpříjemnit její užívání. Je samozřejmé, že možnost drag-and-drop nabízí i Adobe Flex. V článku si ukážeme, jak tuto techniku implementovat.

Seriál: Stručný průvodce po frameworku Flex 4 (6 dílů)

  1. Flex 4: začínáme 25.1.2010
  2. Flex 4: States a Transitions 1.2.2010
  3. Flex 4: Drag-and-drop 8.2.2010
  4. Flex 4 – formuláře a validace 1.3.2010
  5. Flex 4: skinování aplikací 9.3.2010
  6. Flex 4: Webové služby 12.4.2010

Drag-and-drop (DnD) můžeme ve Flexu aplikovat téměř na cokoliv. Některé komponenty mají nativní podporu pro drag-and-drop a umí si přímo poradit s přetahovaným objektem (List, TileList…), u jiných je alespoň možnost si podporu přidat dle vlastního uvážení.

Při implementaci DnD rozlišujeme 3 objekty:

  • Drag Initiator (zde táhnutí začíná – tj. toto je objekt, v němž původně ležel tažený objekt)
  • Drag Proxy (tažený objekt – to je ten, na němž uživatel stiskl tlačítko myši a začal jej přetahovat)
  • Drop Target (cíl vhození, tedy objekt – kontejner, nad nímž je tažený objekt puštěn)

Jedna komponenta může být současně Drag Initiator i Drop Target, záleží na tom, jak si logiku nastavíme.

Jednoduchý Drag-and-drop

Pojďme se podívat na základní možnosti techniky DnD u komponenty, která tuto techniku přímo podporuje, totiž u komponenty List. Jediné, co je potřeba nastavit, je dragEnabled="true" a dropEnabled="true". Tím je přetahování pro daný objekt povolené, a to jak „táhnutí odsud“, tak i „pouštění sem“.

Vytvoříme si dva seznamy, kde první je zdroj (má nastaveno dragEnabled) a druhý cíl (má dropEnabled).

<s:List dragEnabled="true" dataProvider="{new ArrayCollection(['Photoshop','Illustrator','Flash'])}" />
<s:List dropEnabled="true" />

Pokud chcete přetahovat více položek najednou, použijte allowMultipleSelection="true".

Celá aplikace bude vypadat následovně:

<?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" minWidth="955" minHeight="600">
    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
        ]]>
    </fx:Script>
    <s:Label x="10" y="10" text="Nabídka"/>
    <s:Label x="168" y="10" text="Košík"/>
    <s:List dragEnabled="true" dropEnabled="true" allowMultipleSelection="true" dataProvider="{new ArrayCollection(['jablka','hrušky','pomeranče'])}" x="10" y="30" width="150" height="200"/>
    <s:List dragEnabled="true" dropEnabled="true" allowMultipleSelection="true" dataProvider="{new ArrayCollection()}" x="168" y="30" width="150" height="200" ></s:List>
</s:Application>

Můžeme si všimnout, že při přetahování položek z jednoho seznamu na druhý se položky kopírují, což nemusí být vždy žádoucí. Pokud chceme, aby se položky nekopírovaly, ale kompletně celé přesouvaly, použijeme vlastnost dragMoveEnabled="true". Slovo „kompletně“ je zde použito záměrně – v seznamu totiž nemusí být jen primitivní stringy, ale celé komplexní objekty a přetahovaná položka tak může nést mnohem víc informací.

Vlastní Drag-and-drop

Při psaní aplikace ve Flexu může nastat situace, kdy bude potřeba (nebo prostě jen výhodnější) udělat Drag-and-drop podle sebe, na vlastních komponentách. K tomu slouží události Drag třídy UIComponent, ze které dědí všechny standardní komponenty.

Při operacích DnD jsou na různých objektech vyvolány tyto události (samosebou ne v tomto pořadí):

  • u původního kontejneru (drag iniciator): dragStart, dragComplete
  • u cílového kontejneru (drag target): dragEnter, dragOver, dragDrop, dragExit

Význam je zřejmý z názvů – dragStart oznamuje začátek tažení, dragComplete je vyvoláno při dokončení celé operace, dragEnter říká, že objekt byl přetažen nad cílový kontejner, dragOver oznamuje, že se objekt pohybuje nad kontejnerem, dragDrop je vyvoláno při puštění objektu a dragExit oznamuje, že uživatel přetáhl objekt z kontejneru ven, aniž by jej pustil.

V dalším příkladu si názorně ukážeme, jak vybrat ze seznamu libovolný počet prvků a přetáhnout je do textového pole (TextArea). K tomu nám postačí dragEnter a dragDrop.

dragEnter potvrdíme či zamítneme příjem přetahovaných položek – DragManager.acceptDragDrop(cílovýObjekt:UIUComponent. Můžeme navíc například změnit kurzor pomocí  DragManager.showFeedback(DragManager.COPY).

dragDrop zase zpracujeme vhozená data. Po celou dobu – i v dragEnter apod. – máte k přetahovaným datům přístup přes event.dragSource, a to konkrétně pomocí metody dataForFormat. My použijeme ještě hasFormat, abychom se ujistili, že se jedná o formát dat, který jsme schopní zpracovat. Tyto formáty se mohou lišit a můžete si zavést i vlastní formát, pokud budete řešit drag-and-drop kompletně ve vlastní režii.

V tuto chvíli nás bude zajímat formát itemsByIndex, který obsahuje položky z komponenty s:List.

Celý příklad tedy bude ve finále vypadat nějak takhle. Všimněte si, že jsme rozšířili nosnou informaci ze Stringu na objekt obsahující dvě položky – nově i cenu. Pomocí labelField nastavíte, který parametr se má vypisovat. Pokud byste chtěli oba, museli byste použít labelFunction nebo vlastní itemRenderer. Pokud vás zajímá, jak se s nimi pracuje, nahlédněte do dokumentace – itemRenderer je podstatně složitější, ale zato má mnohem víc schopností (práci s ním si ukážeme v některém z dalších dílů).

Flex 4 - drag and drop

<?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" minWidth="955" minHeight="600">
    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
            import mx.core.IUIComponent;
            import mx.events.DragEvent;
            import mx.managers.DragManager;
            protected function textarea1_dragEnterHandler(event:DragEvent):void
            {
                DragManager.acceptDragDrop(IUIComponent(event.target));
                DragManager.showFeedback(DragManager.COPY);
            }
            protected function txt_dragDropHandler(event:DragEvent):void
            {
                if(event.dragSource.hasFormat("itemsByIndex")){
                    var data:Object = event.dragSource.dataForFormat("itemsByIndex");
                    event.target.text = "";
                    for(var i:Object in data){
                        event.target.text += data[i].nazev+": "+data[i].cena+"n";
                    }
                }
            }
        ]]>
    </fx:Script>
    <s:Label x="10" y="10" text="Nabídka"/>
    <s:Label x="168" y="10" text="Košík"/>
    <s:List dragEnabled="true" allowMultipleSelection="true" labelField="nazev" dataProvider="{new ArrayCollection([{nazev:'jablka',cena:10},{nazev:'hrušky',cena:15},{nazev:'pomeranče',cena:20}])}" x="10" y="30" width="150" height="200"/>
    <s:TextArea x="168" y="30" dragEnter="textarea1_dragEnterHandler(event)" dragDrop="txt_dragDropHandler(event)"/>
</s:Application>

Drag-and-drop plně pod kontrolou

Zatím jsme si ukázali drag-and-drop spojený s List komponentou. DragManager však obsahuje metodu doDrag. která umožňuje pracovat s jakoukoliv komponentou (obrázek, tlačítko, video…). Drag-and-drop si tak můžeme upravit od základu podle našich představ. Přestavme si, že chceme tlačítko, které po stisknutí budeme moci přenést a hodit na textové pole. Viz následující příklad:

Flex 4 - drag and drop

Kód není nijak složitý a podstatné informace jsou z něj patrné.

<?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" minWidth="955" minHeight="600">
    <fx:Script>
        <![CDATA[
            import mx.core.DragSource;
            import mx.core.IUIComponent;
            import mx.events.DragEvent;
            import mx.managers.DragManager;
            protected function textinput1_dragEnterHandler(event:DragEvent):void
            {
                DragManager.acceptDragDrop(IUIComponent(event.target));
            }
            protected function textinput1_dragDropHandler(event:DragEvent):void
            {
                event.target.text = event.dragSource.dataForFormat("mujFormat");
            }
            protected function button1_mouseDownHandler(event:MouseEvent):void
            {
                var src:DragSource = new DragSource();
                src.addData(event.target.label,"mujFormat");
                DragManager.doDrag(IUIComponent(event.target),src,event);
            }
        ]]>
    </fx:Script>
    <fx:Declarations>
        <!-- Place non-visual elements (e.g., services, value objects) here -->
    </fx:Declarations>
    <s:Button x="10" y="10" label="Tlacitko, ktere nese nejake cool informace" mouseDown="button1_mouseDownHandler(event)"/>
    <s:TextInput x="10" y="77" width="245" dragEnter="textinput1_dragEnterHandler(event)" dragDrop="textinput1_dragDropHandler(event)"/>
</s:Application>

Drag-and-drop v AIRu a File Promise

V AIRu má vývojář k dispozici poměrně příjemnou funkci, a tou je interakce se soubory z file-systému na klientském počítači. Uživatel tedy může do aplikace v AIRu přetáhnout soubor ze správce souborů, který aplikace dokáže nějak zpracovat – např. jej nahraje na server. K dispozici jsou víceméně stejné události, pouze se liší prefixem native

nativeDragComplete, nativeDragDrop, nativeDragEnter, nativeDragExit, nativeDragOver, nativeDragStart, nativeDragUpdate

Tuto funkci doporučuji prozkoumat a odzkoušet si její fungování, hodně AIRových aplikací zjednodušuje práci ze soubory právě pomocí tohoto způsobu přetahování objektů z OS, a lze s ním vymyslet spoustu užitečných věcí – zpracování obrázků, zabalení souborů, konverze, upload na server atp.

V AIR 2.0 můžete navíc nyní z aplikace „vytáhnout“ soubor a přenést ho do file-systému (na plochu, do Průzkumníka, …) – této technice se říká File Promise, což je soubor, který ještě neexistuje, ale vy už ho fyzicky držíte myší „v ruce“. O tom, jakým způsobem s File Promise pracovat, píše např. Piotr Walczyszyn: File Promises with Adobe AIR

Flex 4 - drag and drop
(Autorem ilustračního obrázku je Piotr Walczyszyn)

K tomuto dílu je opět připraven soubor ukázkových aplikací ke stažení: Flex 4 – Drag and Drop

Komentáře: 4

Přehled komentářů

Gebauer Fungují příklady v FB4 beta2?
Tom Krcha Re: Fungují příklady v FB4 beta2?
Jack Re: Fungují příklady v FB4 beta2?
Tom Krcha Re: Fungují příklady v FB4 beta2?
Zdroj: https://www.zdrojak.cz/?p=3167