Android studio смахивание с края экрана влево

Android studio смахивание с края экрана влево

Мы уже поработали в предыдущем уроке с акселерометром смартфона и сделали программу, способную распознавать движение аппарата в пространстве. В этом уроке мы поработаем над возможностями сенсорного экрана, научимся работать с жестами по дисплею, то есть, как научить наше приложения работать с прикосновениями пальцев пользователя, при чем эти прикосновения не будут направлены на какой нибудь элемент управления (кнопка, переключатель и т.д.).

Начинаем с создания проекта. Названия оставим по умолчанию, но, конечно, можете написать что то свое.

Сразу начнем с работы в основном layout файле activity_main.xml. Добавим туда следующие элементы:

Важным моментом здесь является определение элемента FrameLayout. Именно в нем будет происходить основная работа приложения.

Теперь перейдем к файлу MainActivity.java и немного изменим метод onCreate:

Мы объявили здесь класс под названием PlayAreaView и Android Studio на него ругается, но не пугайтесь, мы это исправим.

А сейчас мы выполним довольно интересную часть нашей работы — создадим холст для рисования жестов. Легкий способ это сделать заключается в том, чтобы создать объект для рисования Canvas (холст) с помощью метода onDraw. Это довольно просто и удобно, так как этот метод имеет всего один параметр: объект Canvas. Рисование в Canvas происходит с помощью вызова метода drawBitmap. Создаем в приложении новый класс по имени PlayAreaView.java и добавляем туда следующий код:

В нашем случае выполнение метода onDraw довольно простое. Как это обычно делается, определите еще и переменную DEBUG_TAG. Основная работа в этой части кода происходит при вызове команды drawBitmap, где первым параметром является изображение для рисования, второй параметр задает матричный объект под названием translate, который, как подсказывает его имя, будет показывать, где именно на экране будет происходить рисование. Этот матричный объект будет связывать все действия пользователя, все его прикосновения к экрану, с холстом.

Классу PlayAreaView нужно создать конструктор, выполняющий его самые базовые, начальные настройки. Так, как приложения будет реагировать на жесты, нам необходимо задать GestureDetector (определитель жестов). GestureDetector это класс, способный опознавать события типа жестов (прикасания пользователя к дисплею), проделывать над полученной от датчиков информацией о жестах математические операции, а потом, с помощью объекта GestureListener, создавать определенную обратную реакцию. О бъект GestureListener обрабатывает входящую в него информацию и выдает ответ, который мы можем видеть и реагировать не него (в нашем случае это будет перемещение изображения по экрану). В GestureDetector существует множество возможностей, но мы ограничимся только самыми необходимыми. Добавим этот метод в код файла PlayAreaView.java:

Взглянем на код немного пристальнее. Сначала мы инициализируем необходимый объект матрицы, который будет помогать нам в рисовании, и оно будет происходить в местах, определенных по умолчанию. Далее мы создаем объект GestureDetector и задаем GestureListener. Ну и напоследок, загружаем стандартную картинку, с которой будем работать в приложении. Вы можете использовать там любое изображение по собственному желанию. Это будет изображение, которое мы с помощью жестов будем заставлять перемещаться по рабочему холсту.

Теперь давайте создадим объект GestureDector, который будет принимать данные о жестах и обрабатывать их. Для этого в том же классе PlayAreaView.java добавим следующее:

В процессе работы с определением жестов с помощью GestureDector также нужно реализовать класс GestureListener. Основные жесты, в которых мы заинтересованы, это двойное нажатие по экрану и направленные движения (влево, вправо и т.д.). Для реализации определения этих движений, класс GestureListener должен выполнять интерфейсы OnGestureListener и OnDoubleTapListener:

После добавления этого класса, как подкласса Activity, добавьте все необходимые для них методы, которых жаждет Android Studio. Например, вот один из них:

Выполнение всех этих методов позволит вам изучить самые различные события, которые улавливает объект GestureDetector. Объект MotionEvent связан с самыми разными событиями, которые могут происходить при нажатии пользователем на экран.

Стоит отметить, что существует еще такой удобный метод, как SimpleOnGestureListener, который объединяет в себе функционал сразу двух интерфейсов: OnGestureListener и OnDoubleTapListener. В нем по умолчанию возвращается значение false.

Первое движение, с которым мы хотим работать в нашем приложении, это прокрутка. Оно происходит тогда, когда пользователь прикасается к экрану и, не отрывая пальца, ведет им в какую либо сторону. Это движение мы можем определить в интерфейсе OnGestureListener с помощью метода onScroll:

Читайте также:  Сони колонка как подключить блютуз андроид

Выполнение этого метода является важным в связи с событием, когда пользователь ведет по экрану пальцем и вместе с этим начинает двигаться изображение на дисплее.

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

В принципе, в этом методе мы просто сбрасываем положение картинки на ее положение по умолчанию.

Следующее движение, которое мы будем определять и использовать, можно назвать инерцией. То есть, мы резким движением как бы толкаем картинку в определенную сторону, убираем палец, а она летит по инерции в указанном направлении, постепенно замедляя скорость до полной остановки. Скорость затухания этого движения задается программистом. Например, почти в каждой игре, где есть движение, есть своя физика процесса в которую входит и эта настройка в том числе. Самая лучшая настройка этого параметра может появиться только благодаря экспериментам и качественному подбору, либо же наугад что мы и сделаем.

В нашем случае, мы будем изменять время разности между событием, спровоцировавшим движение, и остановкой инерциального движения, а потом просто запускать анимацию движения картинки к нужному месту с нужной скоростью. Для этого будет использоваться метод onFling. Задание кажется довольно сложным, но я не дам вам шанса над ним подумать и покажу готовый код:) :

Нам даже не нужно выполнять никаких дополнительных проверок параметров, данные о скорости полностью решают нашу задачу. Скорость будет определяться в пискелях за секунду. Мы также можем использовать данные скорости для решения вопроса о том, где остановить движущийся объект, которым у нас является картинка. В нашем случае, мы используем в своих подсчетах 40% от секунды (то есть 400 мс). Данные о скорости будут передаваться в метод onAnimateMove, где и будет задаваться скорость движения изображения. Почему используется именно 400 мс? Потому, что это значение параметра наиболее качественно подходит к большинству устройств. Используя такое значение, мы будем видеть нормальное, относительно плавное движение, а не скачки или некрасивые замедления. Стоит отметить, что эти настройки скорости и анимации не имеют ничего общего с реальной физикой, просто в данном примере так удобно.

Теперь все жесты, которые нам были интересны, учтены. В методе PlayAreaView.java добавим такой метод:

Он делает две вещи. Во первых, метод переводит (здесь «переводит» означает движение от точки A в B) изображение на расстояние в соответствии с движением пальца, во вторых, аннулирует предыдущее положение изображения. Каждый раз, когда происходит движение, мы будем просто обновлять нашу матрицу, заданную ранее.

Теперь добавим onResetLocation метод:

Этот метод будет просто сбрасывать все настройки на настройки по умолчанию.

При движении картинки в заданном пальцем пользователя направлении нужно настроить анимацию так, чтобы она была плавной, проходила гладко, так сказать. В Android есть встроенные классы для анимации (вспоминаем предыдущие уроки по анимации, вот, вот и вот) но в нашем случае их сложно применить. Создадим для приложения свою собственную анимацию. В Android существуют множество интерполяторов, с помощью которых можно задать различную анимацию. Вот их мы и применим для создания анимации. Давайте создадим метод под названием onAnimateMove :

Здесь мы задали начальное положение, начальное и конечное время. Мы инициализируем анимацию, используя класс OvershootInterpolator, и настраиваем ее основные характеристики. Напоследок для завершения работы над анимацией нужно вызвать еще один метод под названием onAnimateStep:

Вот, в принципе, и все основные шаги, которые нужно выполнить для создания программы, способной распознавать жесты пользователя и реагировать на них. Конечно, руководство далеко от идеала, но здесь можно почерпнуть много интересного и познавательного материала, что поможет немного разобраться в использовании подобных инструментов. Удачи в обучении!

Источник

Sliding экранов внутри приложения

Современные мобильные устройства в первую очередь ориентированы на управление пальцами, в частности жестами и прикосновениями. Эта особенность добавляет определенную специфику в организацию пользовательских интерфейсов. На главную роль выходят интуитивно понятные решения, требующие от пользователя наименьших усилий и при этом ненавязчивые, сохраняющие максимум полезного пространства, т.е. не загромождающие пользовательский интерфейс.

Читайте также:  Система андроид потребляет много заряда

Примером таких решений является переключение между рабочими экранами в Android, где для перемещения от одного экрана к другому достаточно выполнить жест вправо или влево. О возможной реализации подобного решения и пойдет речь в данном посте.

Вместо вступления

Для того чтобы проиллюстрировать, то о чем будет идти речь далее, и тем самым добавить наглядности, я записал небольшое видео работы приложения, которое я сегодня буду делать:

В показанном выше приложении имеются четыре несвязанные View, перемещение между которыми осуществляется жестами вправо/влево по экрану. Содержание View могло быть произвольное, но для простоты восприятия я сделал их разноцветными и пронумерованными.

Подобная функциональность не является базовой, т.е. не имеет полностью готового встроенного решения. А также, как ни странно, не является сильно распространенной, и, наверно, из-за этого не освещена в интернете в достаточной степени.

Разработка

Для реализации приведенного приложения необходимо выполнить следующие шаги:

  1. Найти или реализовать контейнер для удобного хранения и перемещения между View
  2. Перехватить пользовательские жесты и на основании полученной информации сделать вывод в какую сторону «двигать» view
  3. Добавить анимацию для визуализации перемещений между экранами

К счастью, контейнер, отвечающий нашим требованиям, уже присутствует в арсенале Android, называется он ViewFlipper. Создадим пустой проект, и добавим в основной layout элемент ViewFlipper:

Теперь создадим четыре view между которыми будем перемещаться, в моем примере они имеют вид:

Далее необходимо связать имеющиеся view c ViewFlipper. Для этого в методе OnCreate базового Activity добавим следующий код:

Теперь мы можем перемещаться между view вызовами методов showNext() и showPrevious() объекта flipper.

Жесты пользователя возбуждают события OnTouch, для обработки этих событий необходимо реализовать метод:

В этом методе, в объекте класса MotionEvent, присутствует вся необходимая информация и выполненном жесте.

Т.к. нам нужно понять куда был выполнен жест вправо или влево, то мы поступим очень просто: сохраним координату по оси X, при нажатии на экран, и сравним с координатой после того как экран будет отпущен. Если изначальное значение больше, то это движение влево, иначе вправо. Код выглядит достаточно просто:

Осталось добавить анимацию. ViewFlipper как и все наследники ViewAnimator поддерживает методы: setInAnimation(. ) и setOutAnimation(. ), через которые можно задать анимации (Animation) вхождения view в экран и пропадания view с экрана. Но т.к. наша анимация будет отличаться в зависимости от жестов, то придется ее указывать каждый раз заново, исходя из текущей операции. Т.е. метод onTouch нужно модифицировать следующим образом:

Где R.anim.* ресурсы с анимацией появления и исчезания view. Не буду приводить все четыре варианта приведу только первый (все остальные можно будет посмотреть в примере проекта, который я приложу к посту):

Все готово! Проект с примером можете скачать отсюда.

UPD. Вариант ViewFlipper’а без отпускания пальца (изменение метода onTouch):

UPD 2. Если вам больше нравится слайдинг с предпросмотром следующей страницы, то вы можете присмотреться к решениям без ViewFlipper, на базе ViewGroup и scrollTo, пример можете найти, например, здесь.

Заключение

Основное достоинство sliding’а, при правильном его использовании: разгрузка пользовательского интерфейса от избыточных контролов. Как видно, реализация получилась простой, а применение подобного функционала поистине широкое.

Но ложка дегтя все же присутствует. Во-первых, если взглянуть на мой пример в первый раз, то практически невозможно догадаться, что там присутствует sliding (это пример и здесь я такой задачи не ставил), а следовательно применение sliding’а требует наличие других UI-решений поясняющих наличие этого самого sliding’а, например, на тех же home screen’ах Android есть «ползунок-индикатор» показывающий на каком экране находится в данный момент пользователь. Во-вторых, при наличии на view контролов, имеющих собственную реакцию на нажатия, прокрутки, и т.п., вызов метода onTouch внутри ViewFlipper’а будет заблокирован его более ранним перехватом внутри дочернего view, поэтому придется дополнительно побеспокоиться о пробрасывании этого события «наверх» к ViewFlipper.

Источник

Drag и Swipe в RecyclerView. Часть 1: ItemTouchHelper

Существует множество обучающих материалов, библиотек и примеров реализации drag & drop и swipe-to-dismiss в Android c использованием RecyclerView. В большинстве из них по-прежнему используются устаревший View.OnDragListener и подход SwipeToDismiss, разработанный Романом Нуриком. Хотя уже доступны новые и более эффективные методы. Совсем немногие используют новейшие API, зачастую полагаясь на GestureDetectors и onInterceptTouchEvent или же на другие более сложные имплементации. На самом деле существует очень простой способ добавить эти функции в RecyclerView . Для этого требуется всего лишь один класс, который к тому же является частью Android Support Library.

Читайте также:  Android gps от 3000

ItemTouchHelper

ItemTouchHelper — это мощная утилита, которая позаботится обо всём, что необходимо сделать, чтобы добавить функции drag & drop и swipe-to-dismiss в RecyclerView . Эта утилита является подклассом RecyclerView.ItemDecoration, благодаря чему её легко добавить практически к любому существующему LayoutManager и адаптеру. Она также работает с анимацией элементов и предоставляет возможность перетаскивать элементы одного типа на другое место в списке и многое другое. В этой статье я продемонстрирую простую реализацию ItemTouchHelper . Позже, в рамках этой серии статей, мы расширим рамки и рассмотрим остальные возможности.

Примечание. Хотите сразу увидеть результат? Загляните на Github: Android-ItemTouchHelper-Demo. Первый коммит относится к этой статье. Демо .apk -файл можно скачать здесь.

Настройка

Сперва нам нужно настроить RecyclerView . Если вы ещё этого не сделали, добавьте зависимость RecyclerView в свой файл build.gradle .

ItemTouchHelper будет работать практически с любыми RecyclerView.Adapter и LayoutManager , но эта статья базируется на примерах, использующих эти файлы.

Использование ItemTouchHelper и ItemTouchHelper.Callback

Чтобы использовать ItemTouchHelper , вам необходимо создать ItemTouchHelper.Callback. Это интерфейс, который позволяет отслеживать действия перемещения (англ. move) и смахивания (англ. swipe). Кроме того, здесь вы можете контролировать состояние выделенного view -компонента и переопределять анимацию по умолчанию. Существует вспомогательный класс, который вы можете использовать, если хотите использовать базовую имплементацию, — SimpleCallback. Но для того, чтобы понять, как это работает на практике, сделаем всё самостоятельно.

Основные функции интерфейса, которые мы должны переопределить, чтобы включить базовый функционал drag & drop и swipe-to-dismiss:

Мы также будем использовать несколько вспомогательных методов:

Рассмотрим их поочередно.

ItemTouchHelper позволяет легко определить направление события. Вам нужно переопределить метод getMovementFlags() , чтобы указать, какие направления для перетаскивания будут поддерживаться. Для создания возвращаемых флагов используйте вспомогательный метод ItemTouchHelper.makeMovementFlags(int, int) . В этом примере мы разрешаем перетаскивание и смахивание в обоих направлениях.

ItemTouchHelper можно использовать только для перетаскивания без функционала смахивания (или наоборот), поэтому вы должны точно указать, какие функции должны поддерживаться. Метод isLongPressDragEnabled() должен возвращать значение true , чтобы поддерживалось перетаскивание после длительного нажатия на элемент RecyclerView . В качестве альтернативы можно вызвать метод ItemTouchHelper.startDrag(RecyclerView.ViewHolder) , чтобы начать перетаскивание вручную. Рассмотрим этот вариант позже.

Чтобы разрешить смахивание после касания где угодно в рамках view -компонента, просто верните значение true из метода isItemViewSwipeEnabled() . В качестве альтернативы можно вызвать метод ItemTouchHelper.startSwipe(RecyclerView.ViewHolder) , чтобы начать смахивание вручную.

Следующие два метода, onMove() и onSwiped() , необходимы для того, чтобы уведомить об обновлении данных. Итак, сначала мы создадим интерфейс, который позволит передать эти события по цепочке вызовов.

Самый простой способ сделать это — сделать так, чтобы RecyclerListAdapter имплементировал слушателя.

Очень важно вызвать методы notifyItemRemoved() и notifyItemMoved() , чтобы адаптер увидел изменения. Также нужно отметить, что мы меняем позицию элемента каждый раз, когда view -компонент смещается на новый индекс, а не в самом конце перемещения (событие «drop»).

Теперь мы можем вернуться к созданию SimpleItemTouchHelperCallback , поскольку нам всё ещё необходимо переопределить методы onMove() и onSwiped() . Сначала добавьте конструктор и поле для адаптера:

Затем переопределите оставшиеся события и сообщите об этом адаптеру:

В результате класс Callback должен выглядеть примерно так:

Когда Callback готов, мы можем создать ItemTouchHelper и вызвать метод attachToRecyclerView(RecyclerView) (например, в MainFragment.java):

После запуска должно получиться приблизительно следующее:

Заключение

Это максимально упрощённая реализация ItemTouchHelper . Тем не менее, вы можете заметить, что вам не обязательно использовать стороннюю библиотеку для реализации стандартных действий drag & drop и swipe-to-dismiss в RecyclerView . В следующей части мы уделим больше внимания внешнему виду элементов в момент перетаскивания или смахивания.

Исходный код

Я создал проект на GitHub для демонстрации того, о чём рассказывается в этой серии статей: Android-ItemTouchHelper-Demo. Первый коммит в основном относится к этой части и немного ко второй.

Источник

Оцените статью