Назва технології drag and drop перекладається як. Технологія перетягування (drag and drop)

Назва технології drag and drop перекладається як. Технологія перетягування (drag and drop)

Для бібліотеки VCL фірмою Borland реалізована власна версія інтерфейсу Drag & Drop (перекладається як "перетягнути"). Інтерфейс цей внутрішній - передавати і приймати можна будь-які керуючі елементи Delphi всередині форми "(крім самої форми). Він реалізований без використання відповідних функцій API Windows - їх потрібно застосовувати при організації спілкування з іншими завданнями шляхом перетягування.

Натиснувши ліву кнопку миші над елементом управління, ми можемо "перетягнути" його на будь-який інший елемент. З точки зору програміста це означає, що в моменти перетягування і відпускання клавіші генеруються певні події, якими передається вся необхідна інформація - покажчик на перетаскується, поточні координати курсору і ін. Одержувачем подій є той елемент, на якому в даний момент знаходиться курсор. Оброблювач такої події має повідомити системі, чи приймає данньш елемент управління "посилку" чи ні. При відпуску кнопки над приймаючим елементом управління генерується ще одне або два події, в залежності від готовності приймача.

CancelDrag Скасовує поточну drag-and-drop або drag-and-dock операцію.

Функція FindDragTarget (const Pos: TPoint; AllowDisabled: Boolean): TControl;

Функція повертає об'єкт базового класуTControl , До якого належить позиція екрану з координатами, визначеними параметром Pos. Призначений для визначення потенційного одержувача drag-and-drop або drag-and-dock операції. Якщо для зазначеної позиції не існує ніякого віконного засоби управління, то функція повертаєnil . Параметр AllowDisabled визначає, чи будуть враховуватися заблоковані (disabled) об'єкти.

Функція IsDragObject (Sender: TObject): Boolean;

Функція визначає, чи є об'єкт, визначений в параметрі Sender, нащадком класуTDragObject . Дану функцію можна використовувати в якості параметра Source в обробниках подій OnDragOver і OnDockOver для того, щоб визначити чи буде прийнятий перетаскується. також функціюIsDragObject можна використовувати в якості параметра Source в обробниках подій OnDragDrop і OnDockDrop для того, щоб правильно інтерпретувати перетаскується.

Властивості DragMode, DragCursor, методи BeginDrag, OnDragOver, OnDragDrop, OnEndDrag, OnStartDrag, параметр Accept

Процес перетягування за допомогою миші інформації з одного об'єкта в інший широко використовується в Widows.Можно переміщати файли між папками, переміщати самі папки і ін.

Всі властивості, методи і події, пов'язані з процесом перетягування, визначені в класі TControl, що є прабатьком всіх візуальних компонентів Delphi. Тому вони є загальними для всіх компонентів.

Починайте перетягувати визначається властивістю DragMode, яке може встановлюватися в процесі проектування або програмно рівним dmManual або dmAutomatic. Значення dmAutomatic (автоматичне) визначає автоматичне початок процесу перетягування при натисканні користувачем кнопки миші над компонентом. Однак в цьому випадку подія OnMouseDown, пов'язане з натисканням користувачем кнопки миші, для цього компонента взагалі не настає.

Інтерфейс перенесення і прийому компонентів з'явився досить давно. Він забезпечує взаємодію двох елементів управління під час виконання програми. При цьому можуть виконуватися будь-які необхідні операції. Незважаючи на простоту реалізації і давність розробки, багато програмістів (особливо новачки) вважають цей механізм малозрозумілим і екзотичним. Проте використання Drag-and-Drop може виявитися дуже корисним і простим в реалізації. Зараз ми в цьому переконаємося.

Для того щоб механізм запрацював, потрібно налаштувати відповідним чином два елементи управління. Один повинен бути джерелом (Source), другий - приймачем (Target). При цьому джерело нікуди не переміщається, а тільки реєструється в цій іпостасі в механізмі.

Повірте, досить просто перетворити X, Y координати, передаються в параметрах подій OnDragOver і OnDragDrop, в координати форми.

Працюйте з властивостями Left і Top компонента, над яким переміщається курсор. Наведу простий приклад. Помістіть на форму компонент Memo і надайте властивості Align значення alTop. Помістіть на форму панель, також прісвойсте властивості Align значення alTop і задайте невелике значення властивості Height, скажімо 6 або 7 пікселів. Встановіть DragMode на dmAutomatica і DragCursor на crVSplit. Помістіть інший Memo-компонент і встановите Align на alClient. Одночасно виберіть обидва Memo-компонента, панель і створіть загальний обробник події OnDragOver як показано нижче:

182

У цьому прикладі ми вибираємо елемент div і робимо його переміщуються шляхом виклику для нього методу draggable (). Як показано на малюнку нижче, в відкритому документі елемент займає своє звичайне позицію, але після цього його можна перемістити за допомогою покажчика миші в будь-яке місце в вікні браузера:

Можливість перетягування елементів корисна вже сама по собі, але вона приносить ще більше користі, якщо застосовується в поєднанні з взаємодією Droppable, яке описано далі.

Взаємодія Draggable реалізується виключно за рахунок використання специфічної HTML-розмітки і CSS-стилів. Це означає, що дана функціональність буде працювати практично в будь-якому браузері, але наділені нею елементи не зможуть працювати з аналогічними власними коштами Drag-and-drop операційних систем.

Обумовлені специфікацією HTML5 операції Drag-and-drop зазвичай реалізуються з використанням власних механізмів операційних систем. Якщо ви використовуєте механізм Drag-and-drop jQuery UI, то щоб уникнути виникнення конфліктних ситуацій еквівалентні засоби HTML5 краще відключити. З цією метою встановіть для атрибута draggable елемента body документа значення false.

Налаштування взаємодії Draggable

Існує безліч опцій налаштування для взаємодії Draggable. Найбільш важливі властивості, розгляду яких присвячені наступні розділи, наведені в таблиці нижче:

Властивості взаємодії Draggable
властивість опис
axis Обмежує можливості переміщення певними напрямками. Значення за замовчуванням - false, воно означає відсутність обмежень, але можна також вказати значення "x" (переміщення тільки уздовж осі X) або "y" (переміщення тільки уздовж осі Y)
containment Обмежує розташування переміщуваного елемента певної областю екрану. Типи підтримуваних значень описані в таблиці нижче, при розгляді відповідного прикладу. Значення за замовчуванням - false, воно означає відсутність обмежень
delay Визначає час, протягом якого має здійснюватися перетягування елемента, перш ніж він переміститься. Значення за замовчуванням - 0, воно означає відсутність затримки
distance Визначає відстань, на яку користувач повинен перетягнути елемент з його початкової позиції, перш ніж він дійсно переміститься. Значення за замовчуванням - 1 піксель
grid Здійснює примусову прив'язку переміщуваного елемента до осередків сітки. Значення за замовчуванням - false, воно означає відсутність прив'язки

Обмеження напрямків переміщення

Існують кілька способів, за допомогою яких можна обмежити переміщення елемента певними напрямками. Перший з них полягає у використанні опції axis, що дозволяє обмежити напрямок переміщення віссю X або Y. Відповідний приклад наведено нижче:

...

Перетягнути по вертикалі
Перетягнути по горизонталі
запустити приклад

У цьому прикладі ми визначаємо два елементи div, вибираємо їх за допомогою jQuery і викликаємо метод draggable (). Як аргумент цього методу передається об'єкт, який спочатку обмежує переміщення обох елементів div напрямком уздовж осі X. Застосувавши потім метод jQuery filter (), ми отримуємо можливість вибрати елемент dragV без повторного пошуку засобами jQuery по всьому документу і встановити для нього інше дозволений напрямок переміщення - уздовж осі Y. Таким чином, ми отримуємо документ, в якому один елемент div можна перетягувати тільки в вертикальному напрямку, а інший - тільки в горизонтальному. Результат представлений на малюнку:

Обмеження допустимої області переміщення елемента

Можна також обмежити область екрану, в якій допускається перетягування елемента. Для цього використовується опція containment. Формати значень, які можна вказувати в цій опції, описані в таблиці нижче:

Приклад використання опції containment наведено нижче:

...

Перетягнути по горизонталі
Перетягнути всередині батька
запустити приклад

У цьому прикладі можливості переміщення обох елементів обмежені таким чином, що їх можна перетягувати тільки всередині батьківського елементу, в якості якого виступає елемент div з фіксованими розмірами. Для одного з переміщуються елементів div за допомогою опції axis введено додаткове обмеження, яке полягає в тому, що він може переміщатися всередині батьківського елементу тільки в горизонтальному напрямку. Результат проілюстрований на малюнку:

Обмеження можливостей переміщення елемента осередками сітки

Опція grid дозволяє задати прив'язку переміщуваного елемента до осередків сітки. Ця опція приймає в якості значення масив з двох елементів, що визначають ширину і висоту осередків сітки в пікселях. Приклад використання опції grid наведено нижче:

...

перетащи мене
запустити приклад

У цьому прикладі задана сітка з осередками шириною 100 пікселів і висотою 50 пікселів. Коли ви перетягуєте елемент, він "перескакує" з однієї (невидимої) осередки в іншу. Ефект прив'язки є вельми показовим прикладом використання функціональності взаємодій, проте його важко передати за допомогою екранних знімків.

Можна створити ефект прив'язки лише для одного напрямку, вказавши для осі вільного переміщення значення 1. Наприклад, якщо привласнити опції grid значення, то елемент буде прив'язуватися до осередків сітки шириною 100 пікселів при переміщенні по горизонталі, але переміщення по вертикалі буде вільним.

затримка переміщення

Існують дві опції, що дозволяють організувати затримку при перетягуванні переміщуваного елемента. За допомогою опції delay можна задати час в мілісекундах, протягом якого користувач повинен перетягувати пройти показник перш ніж елемент буде дійсно переміщений. Інший вид затримки забезпечується опцією distance, що визначає відстань в пікселях, на яку користувач повинен перетягнути покажчик миші, перш ніж за ним послідує елемент.

Приклад використання обох налаштувань наведено нижче:

...

Блок з затримкою часу
Блок з мінімальним відстанню
запустити приклад

У цьому прикладі є два переміщуються елемента, для одного з яких затримка задана за допомогою опції delay, а для іншого - за допомогою опції distance.

У разі затримки, яка визначається опцією delay, користувач повинен виконувати перетягування протягом заданого часу, перш ніж це призведе до дійсного переміщення елемента. В даному прикладі тривалість цього проміжку становить 1000 мс. Переміщати мишу в цей час зовсім не обов'язково, але на протязі всього періоду затримки кнопка миші повинна залишатися в натиснутому стані, після чого елемент можна буде перемістити, зсунувши миша. Після закінчення часу затримки переміщуваний елемент причепиться до місця розташування покажчика миші з урахуванням обмежень, що накладаються опціями grid, region і axis, про які раніше говорилося.

Опція distance надає схоже вплив, але в цьому випадку користувач повинен перетягнути курсор не менш ніж на задану кількість пікселів в будь-якому напрямку від початкового місця розташування елемента. Після цього переміщуваний елемент стрибкоподібно переміститься до поточного розташування покажчика.

Якщо застосувати обидві настройки до одного і того ж елементу, то переміщуваний елемент не зрушиться з місця до тих пір, поки не будуть виконані обидва критерії затримки, тобто поки спроба перетягування елемента не буде тривати протягом заданого часу і поки курсор не переміститься на задану кількість пікселів.

Використання методів взаємодії Draggable

Всі методи, визначені для взаємодії Draggable, входять в набір базових методів, з якими ви вже познайомилися при розгляді віджетів. Методи, специфічні для взаємодії Draggable, не передбачені, тому ми не будемо розглядати їх детально. Доступні методи наведено в таблиці нижче:

Використання подій взаємодії Draggable

Взаємодія Draggable підтримує простий набір подій, що повідомляють про перетягуванні елементу. Ці події описані в таблиці нижче:

Як і в разі подій віджетів, на ці події також можна реагувати. Приклад обробки подій start і stop наведено нижче:

...

перетащи мене
запустити приклад

У цьому прикладі події start і stop використовуються для зміни текстового вмісту елемента в процесі перетягування. Ця сприятлива можливість є наслідком того, що взаємодія Draggable реалізовано виключно з використанням засобів HTML і CSS: можна використовувати jQuery для зміни стану переміщуваного елемента навіть у той час, коли він рухається по екрану.

Використання взаємодії Droppable

У деяких ситуаціях однієї лише можливості перетягування може бути цілком достатньо, але найбільшу користь воно приносить в тих випадках, коли використовується спільно з взаємодією Droppable.

Елементи, до яких було застосовано взаємодія Droppable (приймаючі елементи), набувають здатність приймати переміщувані елементи, створені за допомогою взаємодії Draggable.

Приймаючі елементи створюються за допомогою методу droppable (), Але для отримання корисної функціональності потрібно створити обробники подій з числа тих, які визначені для цього виду взаємодії. Доступні події наведені в таблиці нижче:

Події взаємодії Droppable
подія опис
create Відбувається в момент застосування взаємодії Droppable до елементу
activate Відбувається, коли користувач починає перетягувати переміщуваний елемент
deactivate Відбувається, коли користувач припиняє перетягувати переміщуваний елемент
over Відбувається, коли користувач перетягує переміщуваний елемент над приймаючим елементом (але за умови, що кнопка миші ще не була відпущена)
out Відбувається, коли користувач перетягує переміщуваний елемент за межі приймаючої елемента
drop Відбувається, коли користувач залишає переміщуваний елемент на приймаючому елементі

Приклад створення простого приймає елемента, для якого визначено єдиний обробник події drop, наведено нижче:

...

Залиш тут
перетащи мене
запустити приклад

У цьому прикладі в документ доданий елемент div, текстовий вміст якого представлено рядком "Залиш тут". Ми вибираємо цей елемент, використовуючи jQuery, і викликаємо метод droppable (), передаючи йому об'єкт з настройками, який визначає обробник для події drop. Відповіддю на всі ці події є зміна тексту переміщуваного елемента за допомогою методу text ().

Створюване в даному прикладі інтерактивну взаємодію категорії Drag-and-drop є найпростішим, але воно створює зручний контекст для пояснення можливостей спільної роботи взаємодій Draggable і Droppable. Різні стадії процесу перетягування елементів проілюстровані на малюнку:

Все це виглядає дуже просто. Ми перетягуємо переміщуваний елемент до тих пір, поки він не опиниться над приймаючим елементом, і відпускаємо його. Переміщуваний елемент залишається там, де він був залишений, і його текстове вміст змінюється у відповідь на наступ події drop. У наступних розділах показано, як використовувати інші події взаємодії Droppable для підвищення комфортності роботи користувача.

Підсвічування цільового приймає об'єкта

Використовуючи події activate і deactivate, можна підсвітити цільової приймає об'єкт, коли користувач починає процес перетягування. У багатьох ситуаціях ця ідея видається дуже плідною, оскільки при цьому користувач отримує надійне вказівку щодо того, які елементи є частиною моделі Drag-and-drop. Відповідний приклад наведено нижче:

... $ (function () ($ ( "# draggable"). Draggable (); $ ( "# droppable"). Droppable ((drop: function () ($ ( "# draggable"). Text ( "Залишено ")), activate: function () ($ (" # droppable "). css ((border:" medium double green ", backgroundColor:" lightGreen "));), deactivate: function () ($ (" # droppable ") .css (" border "," ") .css (" background-color "," ");)));)); ... Запустити приклад

Як тільки користувач починає перетягувати елемент, спрацьовує подія activate - пов'язане з нашим приймаючим елементом, і функція-обробник використовує метод css () для зміни CSS-властивостей border і background-color цього елемента. В результаті цільової приймає елемент підсвічується, вказуючи користувачеві на існування зв'язку між ним і переміщуються елементом.

Подія deactivate використовується для видалення значень CSS-властивостей з приймаючої елемента і його повернення в початковий стан, як тільки користувач відпускає кнопку миші. (Ця подія відбувається всякий раз, коли перетягування елемента припиняється, незалежно від того, залишений переміщуваний елемент на приймаючому елементі або Не залишено.) Цей процес проілюстрований на малюнку:

Обробка перекривання елементів

Технологію Drag-and-drop можна вдосконалити, додавши в неї обробку подій over і out. Подія over відбувається, коли 50% переміщуваного елемента виявляється над будь-якою частиною приймає елемента. Подія out настає тоді, коли перекривають раніше елементи перестають перекриватися. Приклад відповідної реакції на ці події наведено нижче:

$ (Function () ($ ( "# draggable"). Draggable (); $ ( "# droppable"). Droppable ((drop: function () ($ ( "# draggable"). Text ( "Залишено")) , activate: function () ($ ( "# droppable"). css ((border: "medium double green", backgroundColor: "lightGreen"));), deactivate: function () ($ ( "# droppable"). css ( "border", "") .css ( "background-color", "");), over: function () ($ ( "# droppable"). css ((border: "medium double red", backgroundColor : "red"));), out: function () ($ ( "# droppable"). css ( "border", "") .css ( "background-color", "");)));) ); запустити приклад

Тут використані ті ж функції-обробники, що і в попередньому прикладі, але в даному випадку вони пов'язані з подіями over і out. Коли з приймаючим елементом перекривається принаймні 50% переміщуваного елемента, він полягає в рамку і колір його фону змінюється, як показано на малюнку:

Зазначений 50% -ний межа називається порогом перекривання (tolerance), величину якого можна задавати при створенні приймає елемента, як буде показано далі.

Налаштування взаємодії Droppable

Для взаємодії Droppable передбачений ряд властивостей, шляхом зміни яких можна налаштувати його поведінку. Ці властивості перераховані в таблиці нижче:

Властивості взаємодії Droppable
властивість опис
disabled Якщо ця опція дорівнює true, то функціональність взаємодії Droppable спочатку відключена. Значення за замовчуванням - false
accept Звужує безліч переміщуються елементів, на які буде реагувати приймає елемент. Значення за замовчуванням - *, йому відповідає будь-який елемент
activeClass Визначає клас, який буде присвоюватися у відповідь на подію activate і віддалятися у відповідь на подію deactivate
hoverClass Визначає клас, який буде присвоюватися у відповідь на подію over і віддалятися у відповідь на подію out
tolerance Визначає мінімальну ступінь перекривання, при якій відбувається подія over

Обмеження допустимих переміщуються елементів

Можна обмежити безліч переміщуються елементів, які будуть прийматися елементом, наділеним функціональністю взаємодії Droppable, за допомогою опції accept. Як значення опції accept слід привласнити селектор. В результаті цієї події взаємодії Droppable відбуватимуться лише в тому випадку, якщо переміщуваний елемент відповідає зазначеному селектору. Відповідний приклад наведено нижче:

...

Залиш тут
елемент 1
елемент 2
запустити приклад

У цьому прикладі є два переміщуються елемента з ідентифікаторами drag1 і drag2. При створенні приймає елемента використовується опція accept, за допомогою якої ми вказуємо, що прийнятним переміщуються елементом буде тільки елемент drag1.

При перетягуванні елементу drag1 ви будете спостерігати той же ефект, що і в попередніх прикладах. У відповідні моменти для приймаючого елемента будуть запускатися події activate, deactivate, over і out. У той же час, якщо перетягувати елемент drag2, який не відповідає зазначеному в параметрі accept селектору, то ці події запускатися не будуть. Цей елемент можна вільно переміщувати, але він не буде сприйматися приймають елементом.

Зверніть увагу на зміну способу вибору прийнятного переміщуваного елемента, для якого слід викликати метод text (). Коли в документі був всього лише один переміщуваний елемент, для цього вистачало атрибута id:

Drop: function () ($ ( "# draggable"). Text ( "Залишено")),

В даному прикладі є два переміщуються елемента, і вибір по атрибуту id не дасть бажаного результату, оскільки текст в цьому випадку буде завжди змінюватися в одному і тому ж переміщуваний елементі, незалежно від того, який з них є прийнятним для приймаючого елемента.

Вихід полягає в тому, щоб використовувати об'єкт ui, який jQuery UI надає в якості додаткового аргументу кожному оброблювачу подій. Властивість draggable об'єкта ui повертає об'єкт jQuery, що містить елемент, який користувач перетягує або намагається залишити на цільовому елементі, що дозволяє вибрати необхідний елемент наступним чином:

Drop: function (event, ui) (ui.draggable.text ( "Залишено")),

Зміна порога перекривання

За замовчуванням подія over відбувається лише в тих випадках, коли принаймні 50% переміщуваного елемента перекривається з приймаючим елементом. Величину цього порогового перекривання можна змінити за допомогою опції tolerance, яка може приймати значення, зазначені в таблиці нижче:

Найчастіше я використовую два значення, fit і touch, оскільки їх зміст найбільш зрозумілий для користувачів. Значення fit використовується мною в тих випадках, коли перетаскується елемент повинен залишитися в тій області приймає елемента, в яку він був переміщений, а значення touch - коли переміщений елемент повинен повернутися у вихідну позицію (відповідний приклад буде наведено далі). Приклад використання параметрів fit і touch наведено нижче:

Значення clone вказує jQuery UI на те, що необхідно створити копію переміщуваного елемента разом з усім його вмістом і використовувати отриманий результат як допоміжний елемент. Результат представлений на малюнку:

Допоміжний елемент видаляється, коли користувач відпускає кнопку миші над переміщуються елементом, залишаючи переміщуваний і приймає елементи в їх вихідних позиціях.

Як показано на малюнку, вихідний переміщуваний елемент залишається на своєму місці і лише допоміжний елемент переміщається по екрану услід за покажчиком миші. Якщо розміри переміщуваного елемента великі, як в нашому прикладі, то він закриває собою інші елементи документа, так що навіть відстежити позицію приймаючої елемента користувачеві буде важко. З цією проблемою можна впоратися, надавши функцію в якості значення опції helper, як показано в прикладі нижче:

... $ (function () ($ ( "div.draggable") .. png "/\u003e")))); $ ( "# Basket"). Droppable ((activeClass: "active", hoverClass: "hover")); )); ... Запустити приклад

Коли користувач починає перетягувати елемент, jQuery UI викликає функцію, задану параметром helper, і використовує повертається елемент як переміщуваного об'єкта. В даному випадку я використовую jQuery для створення елемента img. Результат представлений на малюнку:

Невелике зображення грає роль заступника переміщуваного елемента, що значно спрощує відстеження інших елементів документа.

Об'єкт ui, який jQuery UI передає подій взаємодії Droppable, містить властивість helper, і це властивість можна використовувати для маніпуляцій допоміжним елементом в процесі його перетягування. Приклад використання цієї властивості в зв'язці з подіями over і out наведено нижче:

... $ (function () ($ ( "div.draggable") .. png "/\u003e")))); $ ( "# Basket"). Droppable ((activeClass: "active", hoverClass: "hover", over: function (event, ui) (ui.helper.css ( "border", "thick solid # 27e6ed")) , out: function (event, ui) (ui.helper.css ( "border", "")))); )); ...

Тут події over і out, а також властивість ui.helper використовуються для відображення рамки навколо допоміжний елемент, коли він перекриває приймає елемент. Результат представлений на малюнку:

Прив'язка до країв елементів

За допомогою опції snap можна домогтися того, щоб переміщуваний елемент як би "притягався" до країв елементів, поряд з якими він проходить. Як значення ця опція приймає селектор. Переміщуваний елемент буде прив'язуватися до країв будь-якого елементу, відповідає вказаному селектору. Приклад використання опції snap наведено нижче:

запустити приклад jQuery UI

Кошик
прив'яжіть тут
перетащи мене

Коли переміщуваний елемент наближається до одного з відповідних елементів, він як би "притягується" до нього таким чином, що їх сусідні краю стикаються. Для такої прив'язки можна вибрати будь-який елемент, а не тільки приймає. У цьому прикладі я додав елемент div і визначив для опції snap значення, яке вибирає в документі даний елемент, а також приймає елемент.

Існує пара допоміжних опцій, що дозволяють більш точно налаштувати поведінку елементів щодо прив'язки. Одна з них - це опція snapMode. З її допомогою можна вказати тип прив'язки. Допускаються наступні значення: inner (Прив'язка до внутрішніх краях елементів), outer (Прив'язка до зовнішніх краях елементів) і both (Прив'язка до всіх краях; використовується за умовчанням).

опція snapTolerance дозволяє вказати, на яку відстань повинен наблизитися переміщуваний елемент до краю елемента-мішені, перш ніж відбудеться прив'язка. Значення за замовчуванням - 20, що означає 20 пікселів. У прикладі використовується значення 50, якому відповідав би прив'язка на більшій відстані. Дуже важливо правильно вибрати цю опцію. Якщо значення опції snapTolerance занадто мало, то користувач може не помітити ефекту прив'язки, а якщо воно занадто велике, то переміщуваний елемент почне здійснювати несподівані скачки, прив'язуючись до далеко розташованих елементів.

Нещодавно у мене з'явилася ідея зайнятися разработкойігри для андроїд. Для початку я вирішив написати шахи. Мені здавалося технологія Drag and Drop відмінно підійде для реалізації механізму переміщення фігур. Для непосвячених зазначу, що метод drag and drop полягає в можливості перетягування одних графічних об'єктів на інші і виконання тієї чи іншої дії після відпускання. Найпростіший приклад - видалення ярлика на робочому столі вашого ПК перетягуванням його в кошик. "Кинувши" ярлик в кошик, ми говоримо системі, що хочемо змусити взаємодіяти ці два об'єкти. Система отримує наш сигнал і вирішує, яку дію їй варто зробити. Drag and drop набула широкого поширення завдяки своїй інтуїтивної ясності. Цей підхід підкріплений нашим досвідом взаємодії з об'єктами реального світу і прекрасно працює у віртуальному середовищі. Що ж стосується шахів, за допомогою drag and drop технологічно простіше визначити клітку, куди користувач перетягнув фігуру, оскільки не потрібно обчислювати номер клітини за координатами точки відпускання. Цю роботу візьме на себе віртуальна машина.

Цілі використання технології Drag n Drop

Використання технології drag and drop дозволяє мені малою кров'ю вирішити три завдання:

  1. Візуалізація ходу. Коли користувач стосується фігури і починає її переміщення по екрану, фігура замінюється більш дрібним малюнком. Таким чином, користувач розуміє що фігура захоплена.
  2. Я обмежив область переміщення фігури розмірами дошки.
  3. Якщо користувач відпустив фігуру в неправильному місці, вона повинна повернутися в початкове положення.

Завдання позначені, приступимо до їх реалізації.

Підміна ImageView при торканні

Всі мої фігури є об'єктами ImageView. На жаль, виявилося що реалізація Drag & Drop в Android не дозволяє "прямо з коробки" здійснювати підміну зображення об'єкта при його торканні. Проте, це завдання цілком вирішувана засобами API. Нам знадобиться виконати ряд нескладних дій:

  1. Створити об'єкт DragShadowBuilder.
  2. Викликати метод startDrag.
  3. Сховати наш ImageView, який відображає фігуру, викликавши метод setVisibility з параметром View.INVISIBLE. В результаті на екрані залишиться тільки об'єкт DragShadowBuilder, що буде сигналом користувачеві про захоплення фігури.

Ці дії необхідно реалізувати в обробнику OnTouchListner об'єкта ImageView. Для цього перевизначити метод onTouch:

@ Override public boolean onTouch (View view, MotionEvent motionEvent) (if (motionEvent. GetAction () \u003d\u003d MotionEvent. ACTION_DOWN) (ClipData clipData \u003d ClipData. NewPlainText ( "", ""); View. DragShadowBuilder dsb \u003d new View. DragShadowBuilder (view); view. startDrag (clipData, dsb, view, 0); view. setVisibility (View. INVISIBLE); return true;) else (return false;))

Все дуже просто. Отже, з підміною зображення розібралися, перейдемо до наступної задачі.

Обмеження області перетягування для функції drag drop

Обмеження області перетягування пов'язано з однією проблемою. Справа в тому, що якщо відпустити фігуру за межами дошки, події drop не станеться, оскільки користувач відпустив об'єкт на порожньому місці, і об'єкту ні з чим взаємодіяти. В результаті фігура не повернеться до свого початкового стану і так і залишиться назавжди захованої. Я вбив багато часу на читання документації, але так і не знайшов способу обмежити область перетягування об'єктів. Осяяння прийшло раптово. Мені зовсім не потрібно обмежувати область, мені потрібно дізнатися чи правильно користувач відпустив фігуру чи ні.

Визначення правильності відпускання
Відповіді на свої питання я знайшов в розділі "handling drag end events" на сайті Android Developers. Ось кілька ключових моментів:

  1. Коли користувач завершує перетягування в обробнику DragListeners генерується подія ACTION_DRAG_ENDED.
  2. У DragListener можна отримати більш детальну інформацію про операції drag, викликавши метод DragEvent.getResult ().
  3. Якщо DragListener повертає true у відповідь на подію ACTION_DROP, виклик getResult також поверне true, в іншому випадку - false.

Таким чином, мені потрібно перехопити подія ACTION_DRAG_ENDED і викликати метод getResult. Якщо він поверне false, значить користувач поцупив фігуру за межі дошки, і мені потрібно перевести ImageView в видимий режим.

@ Override public boolean onDrag (View view, DragEvent dragEvent) (int dragAction \u003d dragEvent. GetAction (); View dragView \u003d (View) dragEvent. GetLocalState (); if (dragAction \u003d\u003d DragEvent. ACTION_DRAG_EXITED) (containsDragable \u003d false;) else if (dragAction \u003d\u003d dragEvent. ACTION_DRAG_ENTERED) (containsDragable \u003d true;) else if (dragAction \u003d\u003d dragEvent. ACTION_DRAG_ENDED) (if (dropEventNotHandled (dragEvent)) (dragView. setVisibility (View. VISIBLE);)) else if (dragAction \u003d \u003d dragEvent. ACTION_DROP & amp; & amp; containsDragable) (checkForValidMove ((ChessBoardSquareLayoutView) view, dragView); dragView. setVisibility (View. VISIBLE);) return true;) private boolean dropEventNotHandled (dragEvent dragEvent) (return! dragEvent. getResult ( );)

Тепер користувач може де завгодно відпускати фігуру, і нічого страшного не станеться.

Визначення допустимих ходів

Остання частина статті присвячена перевірці допустимості ходу, який намагається зробити користувач. Перш ніж докладно приступити до обговорення цієї теми, зроблю невелику ремарку, яка пояснює структуру мого програми. Шахова дошка представлена \u200b\u200bяк TableLayout, а кожна клітина є нащадком LinearLayout і має OnDragListener.

Крім того, кожен OnDragListener посилається на об'єкт "посередника" (mediator), який піклується про взаємодію ігрових об'єктів і запам'ятовує положення поточної клітини.

Коли користувач тягне фігуру над кліткою, можливі наступні дії:

  1. Використання події ACTION_DRAG_ENTERED для установки змінної 'containsDraggable' в true.
  2. Використання події ACTION_DRAG_EXITED для установки змінної 'containsDraggable' в false.
  3. Використання події ACTION_DROP для запиту посередника про допустимість установки фігури в цю клітку.

Нижче наведено код, який реалізує описану логіку

@ Override public boolean onDrag (View view, DragEvent dragEvent) (int dragAction \u003d dragEvent. GetAction (); View dragView \u003d (View) dragEvent. GetLocalState (); if (dragAction \u003d\u003d DragEvent. ACTION_DRAG_EXITED) (containsDragable \u003d false;) else if (dragAction \u003d\u003d DragEvent. ACTION_DRAG_ENTERED) (containsDragable \u003d true;) else if (dragAction \u003d\u003d DragEvent. ACTION_DRAG_ENDED) (if (dropEventNotHandled (dragEvent)) (dragView. setVisibility (View. VISIBLE);)) else if (dragAction \u003d \u003d DragEvent. ACTION_DROP & amp; & amp; containsDragable) (checkForValidMove ((ChessBoardSquareLayoutView) view, dragView); dragView. setVisibility (View. VISIBLE);) return true;)

Як бачите, не залежно від того чи допустимо хід чи ні, ImageView перекладається в видиме стан. Я хотів, щоб користувач бачив, як переміщається фігура. Раніше я згадував, що клітина є нащадком LayoutView. Це зроблено для того щоб простіше переміщати ImageView від клітини до клітини. Нижче наводиться код методу checkForValidMove, який показує, як відбувається переміщення ImageView.

private void checkForValidMove (ChessBoardSquareLayoutView view, View dragView) (if (mediator. isValidMove (view)) (ViewGroup owner \u003d (ViewGroup) dragView. getParent (); owner. removeView (dragView); view. addView (dragView); view. setGravity (Gravity. CENTER); view. showAsLanded (); mediator. handleMove (view);))

Сподіваюся, ця стаття допоможе Вам при розробці власних проектів.

Говорячи про графічному інтерфейсі користувача не можна не сказати про технології Drag and Drop (Буквально: Тягни і Кидай).

Дана технологія заснована на перетягуванні елементів графічного інтерфейсу з джерела в приймач. Інтерфейс доступний тільки за допомогою маніпулятора миша (тачпад, трекбол) або сенсорного екрану.

Елемент, доступний для перетягування, захоплюють і утримують мишкою, перетягуючи одночасно в інше місце. Коли миша встановлена \u200b\u200bв правильну позицію, кнопку миші відпускають, звільняючи об'єкт.

Слід однак відрізняти інтерфейс Drag'n Drop від елементів управління інтерфейсом, що мають в своїх методах методи, що відповідають за переміщення, реалізовані тим же способом. Наприклад, вікно (форма) має можливість переміщення по екрану (перетягуванням за область заголовка). ScrollBox має повзунок прокрутки. Але в обох прикладах перетягування є внутрішнім (для компонента) дією (подією) і ніяким чином не впливає на інші об'єкти системи.

Drag and Drop інтерфейс застосуємо тільки для переміщення об'єкта з контейнера в контейнер, навіть в тому випадку, якщо контейнери різнорідні. Наприклад, перетягування файлу з папки в лист.

Drag and Drop інтерфейс в веб-технологіях

Використання інтерфейсів Drag and Drop в веб-технологіях стало проривом в. Існують оффлайн Drag and Drop редактори (наприклад, DreamWeaver) і онлайн (наприклад, будь-який сучасний конструктор сайтів.

Вже протягом довгого часу існують JavaScript функції, які дозволяють нам створювати drag & drop інтерфейси. Але жодна з цих реалізацій, не є рідною для браузера.У HTML5 є власний метод створення drag & drop інтерфейсів (з невеликою допомогою JavaScript). У цій статті, ми розповімо вам, як цього можна досягти ...

підтримка браузерів

В даний час HTML5 drag & drop підтримується всіма основними браузерами для десктопів (в тому числі IE (навіть в IE 5.5 є часткова підтримка)), але не підтримується жодною з популярних мобільних браузерів.

Drag & Drop події

На кожному етапі перетягування (drag & drop) запускаються різні події для того, щоб браузер знав, який JavaScript код потрібно виконувати. Список подій:

  • dragStart: запускається, коли користувач починає перетягувати елементи;
  • dragEnter: запускається, коли перетаскується елемент вперше перетягується над цільовим елементом;
  • dragOver: спрацьовує при переміщенні миші над елементом, коли відбувається перетягування;
  • dragLeave: запускається, якщо курсор користувача залишає елемент при перетягуванні;
  • drag: приходить в дію кожного разу, коли ми рухаємо мишею під час перетягування нашого елемента;
  • drop: запускається, коли виконується фактичний drop;
  • dragEnd: спрацьовує, коли користувач відпускає кнопку миші при перетягуванні об'єкта.

З урахуванням всіх цих слухачів подій, у вас є хороший контроль над тим, як буде працювати інтерфейс.

об'єкт dataTransfer

Саме тут і відбувається все drag & drop диво. Цей об'єкт містить дані, які були відправлені drag операцією. Дані можуть бути встановлені і отримані різними способами, найбільш важливими з яких є:

  • dataTransfer.effectAllowed \u003d value: повертає дозволені типи дій, можливі значення: none, copy, copyLink, copyMove, link, linkMove, move, all і uninitialized.
  • dataTransfer.setData (format, data): додає певні дані і формат.
  • dataTransfer.clearData (format): очищає всі дані для певного формату.
  • dataTransfer.setDragImage (element, x, y): задає зображення, яке ви хочете перетягнути, х і у значення вказують, де повинен бути курсор миші (0, 0 розташує його вгорі ліворуч).
  • data \u003d dataTransfer.getData (format): як випливає з назви, він повертає дані для певного формату.

Створення drag & drop прикладу

Тепер ми почнемо створювати простий drag & drop приклад. Як ви бачите, у нас є два маленьких divs і один великий, ми можемо перетягнути маленькі діви всередину великого, і навіть перемістити їх назад.

перетягування об'єкта

Перше, що нам потрібно зробити, це створити HTML. Ми робимо div перетягувати за допомогою draggable атрибута:

Коли це буде зроблено, ми повинні визначити JavaScript функцію, яка буде cрабативать, як тільки ми будемо починати пересувати цей елемент:

Function dragStart (ev) (ev.dataTransfer.effectAllowed \u003d "move"; ev.dataTransfer.setData ( "Text", ev.target.getAttribute ( "id")); ev.dataTransfer.setDragImage (ev.target, 100,100) ; return true;)

У цьому коді, ми спочатку оголошуємо, який тип ефекту дозволяємо в операції і встановлюємо його на move. У другому рядку, ми встановлюємо дані для роботи, де текст буде Text і значенням буде ID елемента, який ми перетягуємо. Після цього, ми використовуємо метод setDragImage, який встановить, що ми будемо перетягувати, а потім, де буде курсор під час перетягування, а так як, кубики 200 на 200 пікселів, ми помістили його в самий центр. В кінці, ми повертаємо return true.

Drop об'єкта

Для того, щоб елемент прийняв drop, він повинен прослухати 3 різних події: dragEnter, dragOver, а також drop події. Так що давайте додамо це до нашого HTML5 в div з ID великого (big):

Function dragEnter (ev) (ev.preventDefault (); return true;) function dragOver (ev) (ev.preventDefault ();)

У першій функції ми визначаємо, що має статися, коли елемент, який ми перетягуємо досягне необхідного елемента, де повинен відбутися drop, в даному випадку ми тільки запобігаємо поведінку браузера за замовчуванням. Наступне, в dragOver функції ми просто не допускаємо, щоб стався drop за замовчуванням.

В наступній частині, ми визначаємо функцію, для того, коли елемент буде "кинутий" на бажаної мети:

Function dragDrop (ev) (var data \u003d ev.dataTransfer.getData ( "Text"); ev.target.appendChild (document.getElementById (data)); ev.stopPropagation (); return false;)

У цій останній частині, ми спочатку встановили змінну data, де ми отримуємо всі дані, які доступні для текстового формату, а потім ми додаємо data до div, де потрібно "кинути" елемент.

Зробити секцію drop метою

У демо показано, що два div можуть бути переміщені назад на свої місця. На щастя, додавання ще однієї drop цілі, набагато простіше, ніж ви думаєте. Тому що ці функції у нас вже є і все, що нам потрібно зробити, це додати слухачі подій:

І це все, що потрібно для того, щоб дозволити перетягування div на колишнє місце.

Існує багато drag & drop додатків, які побудовані з використанням JavaScript бібліотек, і часто використовувати їх простіше. Але ми сподіваємося, що в цій HTML5 і JavaScript техніці, ви побачите майбутній потенціал для вирішення ваших завдань.

 

 

Це цікаво: