- Технология Drag and Drop в Android
- Цели использования технологии Drag n Drop
- Подмена ImageView при касании
- Ограничение области перетаскивания для функции drag drop
- Определение допустимых ходов
- Android studio перетаскивание объектов
- Использование Drag-and-drop между различными Activity в Android 7 Nougat
- Описание технологии и разбор примера
- Заключение
- Находки программиста
- воскресенье, 15 июля 2012 г.
- Реализация Drag and Drop в Android
- Drag и Swipe в RecyclerView. Часть 2: контроллеры перетаскивания, сетки и пользовательские анимации
- Контроллеры перетаскивания
- Выделение элемента списка
- Сетки
- Пользовательские анимации смахивания
- Заключение
- Исходный код
Технология Drag and Drop в Android
Недавно у меня появилась идея заняться разработкойигры для андроид. Для начала я решил написать шахматы. Мне казалось технологияDrag and Drop отлично подойдет для реализации механизма перемещения фигур. Для непосвященных отмечу, чтометод drag and drop заключается в возможности перетаскивания одних графических объектов на другие и выполнения того или иного действия после отпускания. Простейший пример — удаление ярлыка с рабочего стола вашего ПК перетаскиванием его в корзину. «Кинув» ярлык в корзину, мы говорим системе, что хотим заставить взаимодействовать эти два объекта. Система получает наш сигнал и решает, какое действие ей стоит предпринять. Drag and drop получила широкое распространение благодаря своей интуитивной ясности. Этот подход подкреплен нашим опытом взаимодействия с объектами реального мира и прекрасно работает в виртуальной среде. Что же касается шахмат, с помощью drag and drop технологически проще определить клетку, куда пользователь перетащил фигуру, поскольку не нужно вычислять номер клетки по координатам точки отпускания. Эту работу возьмет на себя виртуальная машина.
Цели использования технологии Drag n Drop
Использование технологии drag and drop позволяет мне малой кровью решить три задачи:
- Визуализация хода. Когда пользователь касается фигуры и начинает ее перемещение по экрану, фигура заменяется более мелким рисунком. Таким образом, пользователь понимает что фигура захвачена.
- Я ограничил область перемещения фигуры размерами доски.
- Если пользователь отпустил фигуру в неправильном месте, она должна вернуться в первоначальное положение.
Задачи обозначены, приступим к их реализации.
Подмена ImageView при касании
Все мои фигуры представляют собой объекты ImageView. К сожалению, оказалось что реализация Drag & Drop в Android не позволяет «прямо из коробки» осуществлять подмену изображения объекта при его касании. Тем не менее, эта задача вполне решаема средствами API. Нам понадобится выполнить ряд несложных действий:
- Создать объект DragShadowBuilder.
- Вызвать метод startDrag.
- Спрятать наш ImageView, который отображает фигуру, вызвав метод setVisibility с параметром View.INVISIBLE. В результате на экране останется только объект DragShadowBuilder, что будет сигналом пользователю о захвате фигуры.
Эти действия необходимо реализовать в обработчике OnTouchListner объекта ImageView. Для этого переопределим метод onTouch:
Все очень просто. Итак, с подменой изображения разобрались, перейдем к следующей задаче.
Ограничение области перетаскивания для функции drag drop
Ограничение области перетаскивания связано с одной проблемой. Дело в том, что если отпустить фигуру за пределами доски, события drop не случится, поскольку пользователь отпустил объект на пустом месте, и объекту не с чем взаимодействовать. В результате фигура не вернется в свое первоначальное состояние и так и останется навсегда спрятанной. Я убил уйму времени на чтение документации, но так и не нашел способа ограничить область перетаскивания объектов. Озарение пришло внезапно. Мне совсем не нужно ограничивать область, мне нужно узнать правильно ли пользователь отпустил фигуру или нет.
Определение правильности отпускания
Ответы на свои вопросы я нашел в разделе «handling drag end events» на сайте Android Developers. Вот несколько ключевых моментов:
- Когда пользователь завершает перетаскивание в обработчике DragListeners генерируется событие ACTION_DRAG_ENDED.
- В DragListener можно получить более подробную информацию об операции drag, вызвав метод DragEvent.getResult().
- Если DragListener возвращает true в ответ на событие ACTION_DROP, вызов getResult также вернет true, в противном случае — false.
Таким образом, мне нужно перехватить событие ACTION_DRAG_ENDED и вызывать метод getResult. Если он вернет false, значит пользователь утащил фигуру за пределы доски, и мне нужно перевести ImageView в видимый режим.
Теперь пользователь может где угодно отпускать фигуру, и ничего страшного не произойдет.
Определение допустимых ходов
Последняя часть статьи посвящена проверке допустимости хода, который пытается сделать пользователь. Прежде чем подробно приступить к обсуждению этой темы, сделаю небольшую ремарку, объясняющую структуру моего приложения. Шахматная доска представлена как TableLayout, а каждая клетка является потомком LinearLayout и имеет OnDragListener.
Кроме того, каждый OnDragListener ссылается на объект «посредника» (mediator), который заботится о взаимодействии игровых объектов и запоминает положение текущей клетки.
Когда пользователь тащит фигуру над клеткой, возможны следующие действия:
- Использование события ACTION_DRAG_ENTERED для установки переменной ‘containsDraggable’ в true.
- Использование события ACTION_DRAG_EXITED для установки переменной ‘containsDraggable’ в false.
- Использование события ACTION_DROP для запроса посредника о допустимости установки фигуры в эту клетку.
Ниже приведен код, реализующий описанную логику
Как видите, не зависимо от того допустим ли ход или нет, ImageView переводится в видимое состояние. Я хотел, чтобы пользователь видел, как перемещается фигура. Ранее я упоминал, что клетка является потомком LayoutView. Это сделано для того чтобы проще перемещать ImageView от клетки к клетке. Ниже приводится код метода checkForValidMove, который показывает, как происходит перемещение ImageView.
Надеюсь, эта статья поможет Вам при разработке собственных проектов.
Источник
Android studio перетаскивание объектов
В этом уроке мы научимся создавать движение объекта по экрану с полным контролем этого движения прикосновением пальца. У нас на экране будет находится всеми любимое изображение ic_launcher, которое можно будет передвигать по всему экрану в любую точку.
Начнем с создания нового проекта, выбираем Blank Activity, минимальная версия Android будет 2,2+.
Создадим нехитрый интерфейс приложения. Открываем файл activity_main.xml и добавим туда элемент ImageView:
Теперь переходим к написанию самой программы в MainActivity.java. Все происходящее будет вертеться вокруг использования двух вещей — RelativeLayout.LayoutParams и класса MotionEvent. С помощью RelativeLayout.LayoutParams мы запихнем наше изображение в определенные рамки (сделаем его размером 100*100) и будем изменять положение изображения, отслеживая новые координаты положения изображения на экране.
Класс MotionEvent описывает движение с помощью набора значений координат. Он состоит из определенных команд и числовых значений по осям координат, определяющим положение объекта. Например, когда пользователь впервые прикасается к экрану, вызывается команда ACTION_DOWN, а также набор значений X, Y, включающих координаты точки прикосновения.
Из класса MotionEvent у нас будет использовано 2 команды: MotionEvent.ACTION_DOWN — отслеживает факт прикосновения к объекту и начало движения, здесь будут определяться начальные координаты объекта, далее в работу вступает MotionEvent.ACTION_MOVE, в которой происходит динамическое изменение положения объекта за время жеста прикосновения и содержится точка последней остановки, установленная после завершения действия MotionEvent.ACTION_DOWN.
Добавляем в файл MainActivity.java следующий код:
Ну а теперь проверим, работает ли программа, получилось ли желаемое управляемое движение. Запускаем приложение и любуемся результатом:
Наш Андруша успешно двигается по всему экрану, надеюсь у вас также :).
Источник
Использование Drag-and-drop между различными Activity в Android 7 Nougat
Описание технологии и разбор примера
Для передачи данных при перетаскивании используются классы ClipData и DragEvent. В приложении, в котором инициализируется операция перетаскивания, данные упаковываются с помощью ClipData. ClipData представляет собой сложный тип, содержащий в себе один или несколько экземпляров передаваемых данных. ClipData используется для размещения данных в буфере обмена. Для перетаскивания доступны следующие типы данных:
— MIMETYPE_TEXT_HTML: необходим для передачи HTML текста;
— MIMETYPE_TEXT_INTENT: необходим для передачи интента;
— MIMETYPE_TEXT_PLAIN: необходим для передачи обычного текста;
— MIMETYPE_TEXT_URILIST: необходим для передачи URL.
В приложении приемнике на соответствующем элементе интерфейса устанавливается слушатель перетаскивания, который принимает события DragEvent.
Давайте рассмотрим пример использования функции перетаскивания. В примере представлены два приложения: инициализатор (DragNDropExample) и приемник перетаскивания (DragNDropReceiver).
Для того, чтобы приложение отображалось в многооконном режиме необходимо установить в AndroidManifest в секции Application или Activity следующий параметр:
В приложении DragNDropExample реализовано перетаскивание изображения и текста. Файл изображения хранится в папке Downloads. При перетаскивании изображения другому процессу передается URI файла изображения. Инициализация перетаскивания происходит по долгому нажатию на соответствующие элементы.
Устанавливаем слушатель долгого нажатия.
Получаем URI файла для передачи другому процессу. В новой версии Android для получения доступа к файлам, размещенным в мультимедийных папках, необходимо использовать FileProvider.
Создаем объект ClipData и упаковываем в него URI. При создании объекта ClipData указывается тип упакованных данных. Тип MIMETYPE_TEXT_URILIST указывает, что упаковываютсяURI.
Инициализируем перетаскивание, передавая объект ClipData, объект dragShadowBuilder и устанавливая соответствующие флаги. Флаг View.DRAG_FLAG_GLOBAL разрешает перетаскивание между операциями. Флаги View.DRAG_FLAG_GLOBAL_URI_READ и View.DRAG_FLAG_GLOBAL_URI_WRITE разрешают соответственно чтение и запись URI. Для создания тени при перетаскивании используется DragShadowBuilder. В данном примере тенью является сам элемент интерфейса:
Аналогично происходит все для перетаскивания текста:
В приложении приемнике устанавливаются слушатели OnDragListener:
В слушателе задаются действия для определенных событий перетаскивания. В данном примере установлены действия для следующих событий:
— ACTION_DRAG_STARTED: перетаскивание начато;
— ACTION_DROP: пользователь отпустил перетаскиваемый элемент.
Для того чтобы вставка изображения производилась только в ImageView, а текста в TextView необходима соответствующая проверка. В данном участке кода проверяется тип перетаскиваемых данных и сравнивается с необходимым.
Для перетаскивания текста все происходит аналогично.
Ниже приведены скриншоты экрана в процессе перетаскивания
В процессе перетаскивания изображения:
После перетаскивания текста и изображения:
Заключение
Возможность перетаскивать информацию между различными процессами позволяет ускорить обмен данными между приложениями, сделать его более удобным и наглядным для пользователя.
Источник
Находки программиста
Решения конкретных задач программирования. Java, Android, JavaScript, Flex и прочее. Настройка софта под Linux, методики разработки и просто размышления.
воскресенье, 15 июля 2012 г.
Реализация Drag and Drop в Android
Touch-интерфейсы дают нам удивительную возможность «прикоснуться к приложению», манипулировать с элементами на экране самым естественным для человека способом. И нам, разработчикам, грех не использовать такую возможность. Давайте разберёмся, как максимально просто реализовать Drag&Drop в нашем приложении.
В двух словах уточним, какое поведение элемента интерфейса мы хотим получить. Есть пара белых ImageView и один синий прямоугольник. Та из белых картинок, которой мы коснулись будет следовать за пальцем, пока мы её не отпустим. Если мы отпустим её над синим прямоугольником, прямоугольник станет красным, и картинка останется на месте. Если за пределами — картинка вернётся на исходную позицию.
Основная наша цель — сделать всё максимально просто. Кроме Layout-a, описывающего начальное состояние интерфейса, мы напишем всего один класс в сотню строк кода. Итак приступим.
Становимся в исходное положение
Как я и описывал в условии задачи: тут синий прямоугольник и две картинки в RelativeLayout-е. Ничего особенного.
Вот и наши 100 строк кода:
Посмотрим на наш код внимательнее. Вся логика реализована тут с помощью двух listener-ов. Первый OnTouchListener, метод onTouch которого реализует непосредственно наше Activity мы навешиваем на «подвижные» картинки. Задача, которую мы тут решаем — определить какая из картинок под пальцем, сохранить её начальные параметры расположения на случай, если нужно будет вернуться и установить флаг начала перемещения.
Второй OnTouchListener вешаем на самый верхний элемент иерархии View нашего Activity. Он определяет координаты «цели», перемещает картинку и проверяет, не попали ли мы уже в цель.
Источник
Drag и Swipe в RecyclerView. Часть 2: контроллеры перетаскивания, сетки и пользовательские анимации
В первой части мы рассмотрели ItemTouchHelper и реализацию ItemTouchHelper.Callback, которая добавляет базовые функции drag & drop и swipe-to-dismiss в RecyclerView . В этой статье мы продолжим то, что было сделано в предыдущей, добавив поддержку расположения элементов в виде сетки, контроллеры перетаскивания, выделение элемента списка и пользовательские анимации смахивания (англ. swipe).
Контроллеры перетаскивания
При создании списка, поддерживающего drag & drop, обычно реализуют возможность перетаскивания элементов по касанию. Это способствует понятности и удобству использования списка в «режиме редактирования», а также рекомендуется material-гайдлайнами. Добавить контроллеры перетаскивания в наш пример сказочно легко.
Сперва обновим layout элемента (item_main.xml).
Изображение, используемое для контроллера перетаскивания, можно найти в Material Design иконках и добавить в проект с помощью удобного плагина генератора иконок в Android Studio.
Как кратко упоминалось в прошлой статье, вы можете использовать ItemTouchHelper.startDrag(ViewHolder) , чтобы программно запустить перетаскивание. Итак, всё, что нам нужно сделать, это обновить ViewHolder , добавив контроллер перетаскивания, и настроить простой обработчик касаний, который будет вызывать startDrag() .
Нам понадобится интерфейс для передачи события по цепочке:
Затем определите ImageView для контроллера перетаскивания в ItemViewHolder :
и обновите RecyclerListAdapter :
RecyclerListAdapter теперь должен выглядеть примерно так.
Всё, что осталось сделать, это добавить OnStartDragListener во фрагмент:
RecyclerListFragment теперь должен выглядеть следующим образом. Теперь, когда вы запустите приложение, то сможете начать перетаскивание, коснувшись контроллера.
Выделение элемента списка
Сейчас в нашем примере нет никакой визуальной индикации элемента, который перетаскивается. Очевидно, так быть не должно, но это легко исправить. С помощью ItemTouchHelper можно использовать стандартные эффекты подсветки элемента. На Lollipop и более поздних версиях Android, подсветка «расплывается» по элементу в процессе взаимодействия с ним; на более ранних версиях элемент просто меняет свой цвет на затемнённый.
Чтобы реализовать это в нашем примере, просто добавьте фон (свойство background ) в корневой FrameLayout элемента item_main.xml или установите его в конструкторе RecyclerListAdapter.ItemViewHolder. Это будет выглядеть примерно так:
Выглядит круто, но, возможно, вы захотите контролировать ещё больше. Один из способов сделать это — позволить ViewHolder обрабатывать изменения состояния элемента. Для этого ItemTouchHelper.Callback предоставляет ещё два метода:
- onSelectedChanged(ViewHolder, int) вызывается каждый раз, когда состояние элемента меняется на drag (ACTION_STATE_DRAG) или swipe (ACTION_STATE_SWIPE). Это идеальное место, чтобы изменить состояние view -компонента на активное.
- clearView(RecyclerView, ViewHolder) вызывается при окончании перетаскивания view -компонента, а также при завершении смахивания (ACTION_STATE_IDLE). Здесь обычно восстанавливается изначальное состояние вашего view -компонента.
А теперь давайте просто соберём всё это вместе.
Сперва создайте интерфейс, который будут реализовывать ViewHolders :
Затем в SimpleItemTouchHelperCallback реализуйте соотвутствующие методы:
Теперь осталось только, чтобы RecyclerListAdapter.ItemViewHolder реализовал ItemTouchHelperViewHolder :
В этом примере мы просто добавляем серый фон во время активности элемента, а затем его удаляем. Если ваш ItemTouchHelper и адаптер тесно связаны, вы можете легко отказаться от этой настройки и переключать состояние view -компонента прямо в ItemTouchHelper.Callback .
Сетки
Если теперь вы попытаетесь использовать GridLayoutManager , вы увидите, что он работает неправильно. Причина и решение проблемы просты: мы должны сообщить нашему ItemTouchHelper , что мы хотим поддерживать перетаскивание элементов влево и вправо. Ранее в SimpleItemTouchHelperCallback мы уже указывали:
Единственное изменение, необходимое для поддержки сеток, заключается в добавлении соответствующих флагов:
Тем не менее, swipe-to-dismiss не очень естественное поведение для элементов в виде сетки, поэтому swipeFlags разумнее всего обнулить:
Чтобы увидеть рабочий пример GridLayoutManager , смотрите RecyclerGridFragment. Вот как это выглядит при запуске:
Пользовательские анимации смахивания
ItemTouchHelper.Callback предоставляет действительно удобный способ для полного контроля анимации во время перетаскивания или смахивания. Поскольку ItemTouchHelper — это RecyclerView.ItemDecoration, мы можем вмешаться в процесс отрисовки view -компонента похожим образом. В следующей части мы разберём этот вопрос подробнее, а пока посмотрим на простой пример переопределения анимации смахивания по умолчанию, чтобы показать линейное исчезновение.
Параметры dX и dY — это текущий сдвиг относительно выделенного view -компонента, где:
- -1.0f — это полное смахивание справа налево (от ItemTouchHelper.END к ItemTouchHelper.START )
- 1.0f — это полное смахивание слева направо (от ItemTouchHelper.START к ItemTouchHelper.END )
Важно вызывать super для любого actionState , который вы не обрабатываете, для того, чтобы запускалась анимация по умолчанию.
В следующей части мы рассмотрим пример, в котором будем контролировать отрисовку элемента в момент перетаскивания.
Заключение
На самом деле, настройка ItemTouchHelper — это довольно весело. Чтобы не увеличивать объём этой статьи, я разделил её на несколько.
Исходный код
Весь код этой серии статей смотрите на GitHub-репозитории Android-ItemTouchHelper-Demo. Эта статья охватывает коммиты от ef8f149 до d164fba.
Источник