Простая анимация на андроид с исходным кодом. Добавление анимации на основе физики в Android приложения
Анимации, которые кажутся подвижными и реалистичными, как правило, делают пользовательские интерфейсы более привлекательными. Неудивительно, что Material Design уделяет им столько внимания!
Однако, если вы когда-либо пробовали создавать такие анимации, вы знаете, что простые аниматоры и интерполяторы, предлагаемые Android SDK, часто не достаточно хороши. Вот почему недавние версии Android Support Library поставляются с физическим модулем Dynamic Animation (динамичная анимация).
С помощью Dynamic Animation вы можете создавать анимации на основе физики, которые очень напоминают движения объектов в реальном мире. Вы также можете заставить их реагировать на действия пользователя в режиме реального времени. В этом уроке я покажу вам, как создать несколько таких анимаций.
Необходимые условия
Чтобы следовать уроку, убедитесь, что у вас есть следующее:
- Android Studio 3.0 Canary 4 или выше
- Устройство или эмулятор под управлением Android 4.4 или более поздней версии
1. Добавление зависимостей
Чтобы иметь возможность использовать Dynamic Animation в вашем проекте, вы должны добавить его как зависимость implementation в файле build.gradle вашего модуля app:
Implementation "com.android.support:support-dynamic-animation:26.0.0-beta2"
В этом уроке мы собираемся анимировать виджет ImageView . Разумеется, он должен отображать некоторые изображения, поэтому откройте Vector Assets Studio и добавьте в свой проект следующие Material значки:
- нейтральное настроение
- настроение очень удовлетворено
Вот как они выглядят:
Для получения наилучших результатов я предлагаю установить размер значков 56 x 56 dp .
2. Создание анимации Fling
Когда вы подбрасываете объект в реальном мире, вы задаете ему большой импульс (момент движения). Поскольку импульс это не что иное, как произведение массы и скорости, изначально объект будет иметь высокую скорость. Постепенно, впрочем, благодаря трению, он замедляется, пока он не перестанет двигаться полностью. Используя класс FlingAnimation от Dynamic Animation, вы можете имитировать это поведение в своём приложении.
Для демонстрации давайте теперь создадим макет, содержащий всплывающий виджет ImageView , отображающий значок и виджет Button , который пользователи могут нажать, чтобы вызвать анимацию fling. Если вы разместите их внутри виджета RelativeLayout , ваш XML-файл макета будет выглядеть так:
В приведенном выше коде вы увидите, что виджет Button имеет атрибут onClick . Нажав на значок с красным индикатором, который Android Studio покажет рядом с этим, вы можете вызвать обработчик события по клику внутри вашего класса Activity:
Public void flingIt(View view) { // more code here }
Теперь вы можете создать новый экземпляр класса FlingAnimation , используя его конструктор, который ожидает объект View и имя свойства анимирования. Динамическая анимация поддерживает несколько анимационных свойств, таких как масштабирование/scale, трансляция/translation, вращение/rotation и альфа/alpha.
В следующем коде показано, как создать экземпляр FlingAnimation , который может анимировать координату-Х ImageView нашего макета:
// Get a reference to the view ImageView emoji = (ImageView)findViewById(R.id.emoji); // Pass it to the constructor FlingAnimation flingAnimation = new FlingAnimation(emoji, DynamicAnimation.X);
По умолчанию экземпляр FlingAnimation настроен на использование 0 пикселей в секунду в качестве начальной скорости. Это означает, что анимация остановится, как только она начнется. Чтобы имитировать реалистичный запуск движения, вы всегда должны помнить о вызове метода setStartVelocity() и передать ему большое значение.
Кроме того, вы должны понимать, что без трения анимация не остановится. Поэтому вы также должны вызвать метод setFriction() и передать ему небольшое число.
Следующий код настраивает экземпляр FlingAnimation таким образом, что ImageView не выходит за границы экрана пользователя:
FlingAnimation.setStartVelocity(500f); flingAnimation.setFriction(0.5f);
На этом этапе вы можете просто вызвать метод start() для запуска анимации.
FlingAnimation.start();
Если вы сейчас запустите приложение и нажмёте кнопку, вы сможете увидеть анимацию fling.
Стоит отметить, что вы не указываете продолжительность или конечное значение при создании анимации на основе физики - анимация автоматически останавливается, когда она осознает, что её целевой объект не показывает никаких видимых движений на экране пользователя.
3. Имитация пружины - Springs
Динамическая анимация позволяет легко добавить движение пружины в анимацию. Другими словами, это может помочь вам создать анимацию, которая заставит ваши виджеты отскакивать, растягиваться и сплющиваться такими образами, которые кажутся естественными.
Чтобы всё было просто, давайте теперь повторно используем ImageView нашего макета и применим к нему анимацию с эффектом пружинки. Однако, чтобы позволить пользователю запустить анимацию, вам нужно добавить в макет ещё один виджет Button .
Чтобы создать анимацию на основе спружинивания, вы должны использовать класс SpringAnimation . Его конструктор тоже ожидает объект View и анимационное свойство. Следующий код создает экземпляр SpringAnimation , настроенный для анимации координаты Х для ImageView:
// Get a reference to the view final ImageView emoji = (ImageView)findViewById(R.id.emoji); // Pass it to the constructor SpringAnimation springAnimation = new SpringAnimation(emoji, DynamicAnimation.X);
Чтобы управлять поведением анимации на основе пружинки, вам понадобится spring. Вы можете создать его с помощью класса SpringForce , который позволяет вам указать положение покоя качания, коэффициент затухания и жёсткость. Вы можете думать о коэффициенте затухания как о константе, которая, как и трение, несёт ответственность за замедление анимации до её остановки. С другой стороны, жёсткость определяет, сколько силы требуется для растягивания пружины.
Если всё это звучит слишком сложно, хорошей новостью является то, что класс SpringForce предлагает несколько общеназванных констант, которые вы можете использовать для быстрой настройки пружины. Например, следующий код создает пружину, которая и очень упругая и очень гибкая:
SpringForce springForce = new SpringForce(); springForce.setFinalPosition(emoji.getX()); springForce.setDampingRatio(SpringForce.DAMPING_RATIO_HIGH_BOUNCY); springForce.setStiffness(SpringForce.STIFFNESS_LOW);
В приведенном выше коде вы можете видеть, что мы установили значение конечного положения покоя пружины на начальную координату X ImageView . С такой конфигурацией, вы можете представить, что ImageView привязан к жесткой невидимой резиновой ленте, которая быстро тянет ImageView обратно в исходное положение при каждом перемещении.
Теперь вы можете связать пружину с экземпляром SpringAnimation , используя метод setSpring() .
SpringAnimation.setSpring(springForce);
Наконец, перед началом анимации вы должны убедиться, что вы придаёте ему большую начальную скорость, используя метод setStartVelocity() .
SpringAnimation.setStartVelocity(2000f); springAnimation.start();
Если вы запустите приложение сейчас, вы увидите что-то вроде этого:
4. Прослушивание событий анимации
Анимация, созданная с использованием библиотеки динамической анимации, всегда должна запускаться из пользовательского интерфейса. Вы также можете быть уверены, что он начнется, как только вы вызовете метод start() . Однако она выполняется асинхронно. Поэтому, если вы хотите, чтобы вас уведомляли, когда она заканчивается, вы должны прикрепить к нему объект OnAnimationEndListener с помощью метода addEndListener() .
Чтобы увидеть слушателя в действии, давайте изменим значок Material для начала и окончания анимации, отображаемый ImageView , каждый раз при пружинной анимации, которую мы создали на предыдущем шаге. Я предлагаю вам использовать значок ic_sentiment_very_satisfied_black_56dp при запуске анимации и значок ic_sentiment_neutral_black_56dp по окончании. В следующем коде показано, как:
// Change icon before animation starts emoji.setImageResource(R.drawable.ic_sentiment_very_satisfied_black_56dp); // Start animation springAnimation.start(); springAnimation.addEndListener(new DynamicAnimation.OnAnimationEndListener() { @Override public void onAnimationEnd(DynamicAnimation animation, boolean canceled, float value, float velocity) { // Change icon after animation ends emoji.setImageResource(R.drawable.ic_sentiment_neutral_black_56dp); } });
С приведенным выше кодом анимация будет выглядеть так:
5. Анимация нескольких свойств
Конструкторы классов FlingAnimation и SpringAnimation могут принимать только одно анимационное свойство. Если вы хотите одновременно анимировать несколько свойств, вы можете создать несколько экземпляров классов, которые могут стать громоздкими или создать новое настраиваемое свойство, которое кратко отразит все ваши желаемые свойства.
Чтобы создать настраиваемое свойство анимирования, вы должны создать подкласс класса FloatPropertyCompat , который имеет два абстрактных метода: setValue() и getValue() . Как вы могли догадаться, вы можете обновить значения всех желаемых анимационных свойств внутри метода setValue() . Однако в методе getValue() необходимо вернуть только текущее значение какого-либо одного свойства. Из-за этого ограничения обычно вам нужно убедиться, что значения укороченных свойств не полностью независимы друг от друга.
Например, следующий код показывает вам, как создать настраиваемое свойство под названием scale , которое может равномерно анимировать свойства SCALE_X и SCALE_Y виджета:
FloatPropertyCompat
Теперь, когда наше свойство готово, вы можете использовать его, как и любое другое анимационное свойство. В следующем коде показано, как создать с ним объект SpringAnimation:
SpringAnimation stretchAnimation = new SpringAnimation(emoji, scale);
При создании анимации, использующей настраиваемое свойство, неплохо также вызвать метод setMinimumVisibleChange() и передать ему многозначительное значение, чтобы убедиться, что анимация не потребляет слишком много ЦП. Для нашей анимации, которая масштабирует виджет, вы можете использовать следующий код:
StretchAnimation.setMinimumVisibleChange(DynamicAnimation.MIN_VISIBLE_CHANGE_SCALE);
Вот как выглядит анимация настраиваемого свойства:
Заключение
Теперь вы знаете основы работы с Dynamic Animation. С помощью методов, которые вы узнали в этом уроке, вы можете создать убедительные анимации на основе физики за считанные минуты, даже если у вас мало знаний о Ньютоновской физике.
Чтобы узнать больше о динамической анимации, обратитесь к официальной документации . В то же время ознакомьтесь с некоторыми другими нашими недавними статьями о разработке приложений для Android!
Уже довольно давно в Андроиде существует возможность использовать векторные ресурсы вместо png нарезки. Такая возможность появилась с релизом Android 5.0 Lollipop и API 21. Для более ранних версий системы, мы можем использовать AppCompat (библиотека совместимости), благодаря которой статичный вектор будет работать с API 7 (Android 2.1), а анимированный с API 11 (Android 3.0 Honeycomb).
Векторные ресурсы, в отличие от обычной нарезки, занимают примерно в 10 раз меньше места. Нет необходимости адаптировать графику под разные плотности экранов. Кроме того, можно переиспользовать ресурс в разном контексте, размере и цвете.
Другим важным преимуществом является возможность добавить анимацию. Да, конечно, анимацию можно сделать и при использовании png - например спрайтовую, но такая анимация будет занимать в десятки раз больше места с учетом поддержки всех разрешений.
Вектор на Андроид?
Прежде чем приступить к созданию векторных ассетов, необходимо разобраться что из себя представляет вектор на Андроиде. Понимание структуры очень важно, так как в настоящий момент не существует инструментов для удобного создания и визуального контроля анимации.
К сожалению (или к счастью), в Андроиде нельзя использовать svg файлы напрямую, по крайней мере, без использования сторонних библиотек. Причина очень проста и состоит в том, что SVG формат очень комплексный и богатый на возможности и поддержка столь богатого функционала сложна и не целесообразна для таких простых вещей как иконки, ну и не стоит забывать о проблеме производительности и совместимости. Именно поэтому в андроиде используют более простой формат, который, тем не менее, во многом похож на svg.
Векторная графика представлена в виде двух классов VectorDrawable и AnimatedVectorDrawable. Из названия классов понятно, что первый отвечает за статичный вектор, а второй за его анимацию. Классы описываются обычным XML ресурсом.
Для начала рассмотрим VectorDrawable, который имеет следующую структуру:
В элементе
Для того чтобы добавить анимацию мы используем класс ObjectAnimator который просто применяем на объекты VectorDrawable. Мы можем применять анимацию как к общей группе так и к конкретному
Раньше для реализации анимации в приложении необходимо было использовать как минимум 3 xml файла: 1 файл для VectorDrawable который необходимо анимировать, другой для аниматора описывающего анимацию и последний файл - объединяющий непосредственно аниматор и VectorDrawable. Чем сложнее анимация, тем больше файлов необходимо создавать, что часто приводило к путанице.
На Google I/O 2016 был представлен новый формат - XML bundle. Он позволяет описывать векторную анимацию одним файлом.
Пример XML Bundle
По сути, мы всю необходимую информацию размещаем в AnimatedVectorDrawable. Собрать такой файл очень легко, на картинке выделены куски, которые просто вырезаются из соответствующих ресурсов и вставляются между специальными aapt тэгами.
Готовим вектор под андроид
Для начала нам нужен любой графический редактор, который умеет на выходе выдавать svg файл. К счастью, их великое множество: Photoshop, Illustrator, Sketch, Inkscape, Affinity Designer и т.д.
При создании векторного изображения нужно использовать самые базовые инструменты, так как тени и прочие фильтры просто не будут работать.
Для примера я сделал простую иконку замка и разделил её на два шейпа (группы) для последующей анимации. Сохраняем в svg и обязательно проверяем корректность экспорта. Очень часто проблемы возникают со stroke и от избыточной вложенности объектов. Как правило, старайтесь по максимуму объединять всё в один объект, а stroke переводить в shape(outline).
Конвертация SVG в XML
Есть несколько способов сделать конвертацию svg файла в xml.
Первый способ - это сделать всё руками. Это конечно, не очень удобно, но ничего сложного тут нет. Просто переносим куски из svg в xml используя правильные имена параметров. Ниже я выделил куски, которые практически полностью совпадают.
Второй способ - В Android Studio есть инструмент Vector Asset Studio, который позволяет автоматически выполнить перевод SVG файла в XML. Ресурсы можно выбирать из библиотеки иконок или указать свой SVG файл. Благодаря превью можно сразу оценить корректность экспорта. Есть полезные настройки.
Третий способ - это использовать онлайн инструменты, например
В ribot мы заботимся о создании красивого и значимого опыта для людей, в котором движение играет важную роль.
Став свидетелем вдохновляющей речи на Droidcon London, я решил покопаться глубже в элементах движения на Android. Исходя из этого, я собрал все свои находки, чтобы помочь разработчикам и дизайнерам узнать, насколько это просто добавить красивое движение в приложениях на Android.
Если вы хотите попробовать сделать эти анимации сами, каждый из этих примеров упакован в Android приложении на Github.
Я люблю движение, оно не только повышает взаимодействие, но оно сразу же обращает на себя внимание. Подумайте о приложениях, которые вы используете и об анимационном дизайне, особенно то, как приятно, легко, свободно и естественно они выглядят.
Falcon Pro: Даже едва заметные движения могут показать огромную разницу в пользовательском опыте
Теперь сравните их с теми приложениями, которые вы любите, и которые не вызывают таких же чувств.
Medium: Насколько я люблю Medium приложение, но ему действительно не хватает движения в тех областях, в которых она заслуживает его иметь.
Все в деталях
Мы можем использовать эти эффекты движения разными способами:
- Переводить пользователей через навигационный контекст
- Усиливать элементарную иерархию
- Объяснять изменения между компонентами, отображаемыми на экране
Целью данной статьи является показать вам, насколько просто осуществить движение в ваших приложениях, там где оно может принести значительную пользу - так давайте начнем.
Обратная связь по сигналу касания
Обеспечение обратной связи, когда пользователь касается экрана, помогает общаться в визуальной форме, чтобы осуществилось взаимодействие. Эти анимации не должны отвлекать пользователя, но должны его веселить, вносить ясность и поощрять дальнейшее изучение.
Android фреймворк обеспечивает пульсирующее состояние для этого уровня обратной связи, которое может быть использовано для установки фона анимационного образа на одном из следующих:
Android:attr/selectableItemBackground - Показывает пульсирующий эффект в пределах границ образа.
Пульсация начинается в точке касания, заполняя фон представленного образа
?android:attr/selectableItemBackgroundBorderless - Показывает пульсирующий эффект, выходящий за границы представленного образа.
Круговой пульсирующий эффект начинается в точке касания, заполняя радиус, выходящий за пределы представленного образа
View Property Animator
View Property Animator был введен на уровне API 12, что позволяет просто и эффективно выполнять анимационные операции (параллельно) на некоторых свойствах образа, используя один экземпляр Animator.
Здесь я делаю анимации на все свойства, представленные ниже.
alpha ()- Устанавливает значение альфа, чтобы сделать анимацию
ScaleX ()& ScaleY () - Уравновешивает обзор на своей Х и / или Y оси
translationZ ()- Переводит обзор на своей оси Z
setDuration ()- Устанавливает продолжительность анимации
setStartDelay ()- Устанавливает задержку анимации
setInterpolator ()- Устанавливает интерполяции анимации
setListener ()- Устанавливает слушателя, чтобы знать, когда анимация начинается, заканчивается, повторяется или отменена.
Примечание: Когда слушатель был установлен в данном изображении, и если вы осуществляете иные анимации на этой же точке и не хотите использовать эту функцию обратного вызова, то вы должны установить слушателя на NULL.
Это также просто и аккуратно реализовать программно:
mButton.animate():
TranslationZ(10f)
SetInterpolator(new FastOutSlowInInterpolator())
SetStartDelay(200)
SetListener(new Animator.AnimatorListener() {
public void onAnimationStart(Animator animation) { }
public void onAnimationEnd(Animator animation) { }
public void onAnimationCancel(Animator animation) { }
public void onAnimationRepeat(Animator animation) { }
Примечание: Мы на самом деле не должны вызывать start () на нашем анимационном застройщике, так как анимация запускается автоматически, как только мы одновременно прекращаем заявлять об анимации. Если это так, то анимация не начнется до следующего обновления из очереди событий инструментария интерфейса.
Примечание: Для обеспечения обратной совместимости, вы можете использовать класс ViewCompat для реализации ViewPropertyAnimator из Android API версии 4 и выше.
Как и View Property Animator, Object Animator позволяет нам выполнять анимацию на различных свойствах целевого изображения (как в коде так и ресурсах XML-файлов). Тем не менее, есть несколько отличий:
Object Animator только позволяет анимации существовать в единственном состоянии на один образец, например, за шкалой X следует шкала Y
Тем не менее, она позволяет анимации существовать в обычном состоянии, например, цвет переднего плана образа.
Используя пользовательские Свойства или Состояния, чтобы сделать анимацию масштабирования изображения и изменения цвета переднего плана, мы можем получить следующее:
Используя Custom Property, мы можем создать один экземпляр Object Animator вызвав ObjectAnimator.оfInt (), где мы заявляем:
Вид- Вид, чтобы применить анимацию
Свойство- Свойство для анимации
Первоначальный цвет- Цвет, с которого анимационный вид начинается
Целевой цвет- Цвет, с которым данный образ должен ожить
private void animateForegroundColor(@ColorInt final int targetColor) {
ObjectAnimator animator =
ObjectAnimator.ofInt(YOUR_VIEW, FOREGROUND_COLOR, Color.TRANSPARENT, targetColor);
animator.setEvaluator(new ArgbEvaluator());
animator.setStartDelay(DELAY_COLOR_CHANGE);
animator.start();
}
Затем мы устанавливаем оценщика (мы используем ArgbEvaluator, так как мы делаем анимацию между значениями цвета), устанавливаем задержку и начинаем () анимацию.
Мы создаем экземпляр ObjectAnimator используя оfFloat (), потому что мы не делаем анимацию целочисленных значений при работе с размерами образов
Вместо custom property, мы используем свойства изображения - как View.SCALE_X так и View. SCALE_Y
private void resizeView() {
final float widthHeightRatio = (float) getHeight() / (float) getWidth();
resizeViewProperty(View.SCALE_X, .5f, 200);
resizeViewProperty(View.SCALE_Y, .5f / widthHeightRatio, 250);
}
private void resizeViewProperty(Property
float targetScale,
int durationOffset) {
ObjectAnimator animator = ObjectAnimator.ofFloat(this, property, 1f, targetScale);
animator.setInterpolator(new LinearOutSlowInInterpolator());
animator.setStartDelay(DELAY_COLOR_CHANGE + durationOffset);
animator.start();
}
Наконец, нам надо «оживить» наш образ с измененным размером вне экрана. В этом случае, мы используем AdapterViewFlipper, чтобы вместить наши образы, которые мы анимируем вне экрана. Использование этого означает, что мы можем вызвать showNext () на образце ViewFlipper и он займется анимационными образами вне экрана используя анимацию, которую мы определили. Затем, следующий образ автоматически будет оживать на экране, также используя входящую анимацию, которую мы также определили.
Интерполяторы
Интерполятор может быть использован для определения скорости изменения для анимации, то есть скорость, ускорение и поведение при анимации могут быть изменены. Несколько различных типов, доступных интерполяторов и различия между некоторыми из них являются едва заметными, так что я предлагаю попробовать их на этом устройстве.
- Без Интерполятора - Вид оживает без вариаций в скорости изменения
- Быстро - Вне линии - Внутри
Образ начинает анимацию и заканчивается линейным движением
- Быстро - Медленно - Внутри
Образ начинает анимацию быстро и замедляется к концу
- Линейно - Медленно - Внутри
Образ начинается с линейных движений и замедляется к концу
- Ускорение - Замедление
Образ начинает появляется с ускорения в начале анимации, и постепенно замедляется, когда подходит к концу
- Ускорение- Образ постепенно ускоряется, пока анимация не закончится
- Торможение- Образ постепенно замедляется до тех пор, пока анимация не закончится
- Опережение- Образ начинается с небольшого поворота указанной анимации, прежде чем она станет двигаться стандартным образом
- Предвидеть - Проскакивать- Также как и в Опережении, но движение «тянущее назад», которое происходит во время анимации немного более преувеличено
- Прыгающий Интерполятор- Образ оживает в эффекте «отскок» до того, как дойдет до финиша
- Линейный Интерполятор- Образ оживает от начала до конца линейным и плавным движением
- Проскакивающий Интерполятор- Образ «оживляет» преувеличение данного значения, втягиваясь обратно до требуемого значения
Круговое оживление
Анимация CircularReveal или Круговое оживление использует отсеченный круг, чтобы либо раскрыть, либо скрыть группу элементов пользовательского интерфейса. Кроме помощи в обеспечении визуальной преемственности, это также приятное взаимодействие, для того чтобы помочь усилить его с пользователем.
Как было показано выше, мы начинаем с использования View Property Animator, чтобы скрыть кнопку Floating Action перед началом оживления анимации на наших глазах. Настройка нашего круга оживления требует определить всего лишь несколько атрибутов:
- startView- вид, с которого CircularReveal начнется с (т.е. сжатый вид)
- centerX- Центр координирует для X-оси в нажатом виде
- centerY- Центр координирует для Y-оси в нажатом виде
- targetView- Вид, который надо создать
- finalRadius- Радиус отсечения круга, равный гипотенузе наших значений - centerX и centerY
int centerX = (startView.getLeft() + startView.getRight()) / 2;
int centerY = (startView.getTop() + startView.getBottom()) / 2;
float finalRadius = (float) Math.hypot((double) centerX, (double) centerY);
Animator mCircularReveal = ViewAnimationUtils.createCircularReveal(
targetView, centerX, centerY, 0, finalRadius);
Оконные Переходы
Настройка переходов, используемых для навигации между транзакциями, позволяет производить более сильные визуальные связи между состояниями приложения. По умолчанию мы можем настроить следующие переходы:
- вход- Определяет, как образы транзакции выходят на сцену
- выход- Определяет, как образы транзакции уходят со сцены
- войти снова- Определяет, как транзакция входит снова после ранее сделанного выхода
- общие элементы- Определяет, как обмениваются образы переходов между транзакциями
Как и в 21 уровне API, появилось, и было введено несколько новых переходов:
Взрывной переход позволяет образам выходить со всех сторон экрана, создавая взрывной эффект в нажатом виде.
Взрывной эффект работает очень хорошо на макетах, основанных на сетке.
Этот эффект прост в реализации - начнем с того, что вам нужно создать следующий переход в RES res/transition каталоге.
Все, что мы сделали здесь:
- Объявили взрывной переход
- Установили продолжительность в 300 миллисекунд
Либо программно:
Transition explode = TransitionInflater.from(this).inflateTransition(R.transition.explode);
getWindow().setEnterTransition(explode);
Слайд
Слайд переход позволяет вам скользить в или из транзакции либо с правой стороны, либо с нижней части экрана. Хотя вы могли прийти к этому и ранее, этот новый переход является гораздо более гибким.
Слайд переход позволяет последовательно скользить в дочерние образы
Этот переход, вероятно, будет общим при переключении транзакций, я особенно полюбил правый слайд из-за его жидкообразного состояния. Опять же, это легко сделать:
android:slideEdge=“end“/>
Здесь мы:
- Объявляем слайд переход
- Устанавливаем переходный slideEdge,чтобы закончить на этом (справа), таким образом, слайды идут справа - нижний слайд должен быть установлен внизу
Угасание
Угасающий переход позволяет перейти к транзакции внутри или снаружи, используя угасающий эффект.
Угасающий переход прост, хотя переход с угасанием приятен глазу.
Создать его даже проще, чем предыдущие переходы:
Здесь мы:
- Объявляем угасающийпереход
- Устанавливаем продолжительность до 300 миллисекунд
Оптимизация переходов
Несмотря на эксперименты, я нашел пару подходов, которые могут помочь улучшить эффекты перехода, названные выше.
Разрешение переходам содержимого окон - вы должны включить следующий атрибут в темах, которые унаследованы из материальной темы:
Включение / выключение совпадающих переходов - При переходе, может быть задержка, когда одно действие ждет, пока другое завершит свой переход, прежде чем он сможет начать свой собственный. В зависимости от случая использования, переходы, как правило, выглядят более гибкими и естественными, если вы включите эти атрибуты:
Исключаем Образы из переходов - Иногда мы можем не захотеть создавать переходы для всех наших образов транзакций. Я обнаружил, что в большинстве случаев, строка состояния и панель инструментов вызывали глюки переходов. К счастью, мы можем исключить определенные виды, которые были включены в наши переходы:
Панель инструментов и панель действий - При переходе между действиями с использованием Панели действий на использование панели инструментов (и наоборот), иногда я обнаруживал, что переход не всегда был гладким. Чтобы исправить это, я убедился, что эти два вида деятельности, участвующие в переходе, используют один и тот же компонент.
Продолжительность перехода - Вы не хотите, чтобы пользователь ждал слишком долго, но вы также не хотите создавать компоненты, появляющиеся на скорости света. Это зависит от перехода, который вы используете, так что лучше поэкспериментировать, но я обнаружил, что длительность 200-500 мс работает в большинстве случаев.
Общие элементы переходов
Общие элементы переходов позволяют оживить переходы между общими образами через транзакцию, это создает более приятные переходы и дает пользователю лучше ощутить свое путешествие.
Здесь, образ из нашего первого действия масштабируется и переводится в образ заголовка в нашем втором действии
В наших макетах, мы должны связать любые общие образы с использованием атрибута transitionName - он устанавливает переходные отношения между образами. Ниже приведены общие образы из выше данной анимации:
Это общие образы, что означает - они будут оживать друг с другом во время перехода действий
Для перехода между этими двумя мы начинаем с объявления имени общего перехода, выполненный, с помощью атрибута transitionName в XML макетах.
android:transitionName=“@string/transition_view“/>
android:transitionName=“@string/transition_view“/>
После того, как это будет сделано, мы создаем Pair объект в действии 1), содержащий наш переходный образ, и его transitionName. Затем мы передаем его в примерные варианты транзакций, например (ActivityOptionsCompat), так чтобы оба действия были в курсе общих компонентов. Оттуда мы начнем свою транзакцию, через примерный вариант:
Pair participants = new Pair<>(mSquareView, ViewCompat.getTransitionName(mSquareView));
ActivityOptionsCompat transitionActivityOptions =
ActivityOptionsCompat.makeSceneTransitionAnimation(
SharedTransitionsActivity.this, participants);
ActivityCompat.startActivity(SharedTransitionsActivity.this,
intent, transitionActivityOptions.toBundle());
Разделение этих образов, в то время как происходит переход, действительно помогает завершить переход
Вот переход между этими двумя образами, а что касается образов во втором действии, который скользит снизу?
(Те что слева)
Я рад, что вы спросили! Этого также просто достичь, как показано ниже:
Slide slide = new Slide(Gravity.BOTTOM);
slide.addTarget(R.id.view_separator);
slide.addTarget(R.id.text_detail);
slide.addTarget(R.id.text_close);
getWindow().setEnterTransition(slide);
Как вы видите, мы создаем новый образец Слайд перехода, добавив целевые представления для перехода и установив слайд в качестве перехода входа транзакции.
Пользовательские Переходы
У нас также есть возможность создавать свои собственные переходы, используя любую анимацию из API, которую мы рассмотрели до сих пор. Например, мы можем взять Shared Element переходы на один шаг дальше, чтобы превратиться в переходный образ - это может пригодиться, когда мы хотим отобразить диалоги (или аналогичные всплывающие образы), как показано ниже:
Это движение помогает направлять внимание пользователя между составными состояниями
Давайте коротко остановимся на том, что происходит здесь:
- Мы начинаем с создания SharedTransition, проходя в нажатом состоянии вместе с именем перехода, чтобы ссылаться на общий компонент
- Далее мы создаем экземпляр ArcMotion, это позволяет нам создать изогнутый эффект движения при переходе между двумя образами
- Затем мы расширяем ChangeBounds, чтобы создать пользовательский переход и трансформировать две формы (у нас есть отдельный класс для кнопки и FAB). Здесь мы переопределяем различные методы из класса, так что мы можем оживить требуемые свойства. Мы воспользуемся ViewPropertyAnimator, чтобы оживить прозрачность диалоговых образов, ObjectAnimator, чтобы оживить образы между двумя видами цвета и образец AnimatorSet, чтобы мы смогли анимировать оба этих эффекта вместе.
Анимированный вектор вводимого коэффициента
По API версии 21 (Lollipop), AnimatedVectorDrawable может быть использован для анимации VectorDrawable свойств для получения анимации drawable.
Теперь легко сделать несколько различных видов анимации на вводимом коэффициенте
Но как мы это делаем? Ну, давайте взглянем на это:
Он состоит из нескольких различных файлов, и мы начинаем с создания наших двух отдельных векторных файлов каждый из которых имеет несколько свойств:
- Высота и ширина- Фактический размер векторного изображения
- Viewport высоты и ширины- Объявляет размер виртуального холста, на котором нарисованы векторные дорожки
- Название группы- Объявите группу, к которой принадлежит дорожка
- Сводные X & Y- Объявите стержень, используемый для групповой шкалы и вращения
- Траектория цвета заливки- Цвет заливки траектории вектора
- Траектория данных- Объявите данные векторного пути, используемого для рисования вектора
Примечание: Все свойства ссылок хранятся в общем строчном файле, что помогает хранить элементы в порядке и аккуратности.
android:width=“56dp“
android:viewportWidth=“24.0“>
android:pivotX=“12“
android:pivotY=“12“>
android:pathData=“@string/path_add“/>
Вектор генерируется из нашего ic_add.xml файла (ниже)
android:width=“56dp“
android:viewportHeight=“24.0“
android:viewportWidth=“24.0“>
android:pivotX=“12“
android:pivotY=“12“>
android:pathData=“@string/path_remove“/>
Вектор генерируется из нашего ic_remove.xml файла (ниже)
Далее мы заявляем файлы Animated Vector Drawable , которые устанавливают как Вектор Drawable так и анимации, используемые для каждого «растяжимого» состояния (Добавить или Удалить). Глядя на добавленный или удаленный анимационный вектор, мы объявляем цель:
Анимация из одного состояния в другое
Анимация вращения вводимого коэффициента
android:drawable=“@drawable/ic_add“>
android:animation=“@animator/add_to_remove“ />
android:animation=“@animator/rotate_add_to_remove“ />
Затем мы должны создать каждый из файлов, упомянутый в этих целях.
Изменение состояния вводимого коэффициента
В add_to_remove.xml мы используем ObjectAnimator, чтобы трансформироваться между формами, используя следующие свойства:
- PropertyName- Свойство анимации
- valueFrom- Начальное значение для векторного пути
- valueTo- Целевое значение для векторного пути
- Продолжительность- Продолжительность анимации
- интерполятор- Интерполятор, используемый для анимации
- ValueType- Тип значения, который мы оживляем
android:propertyName=“pathData“
android:valueFrom=“@string/path_add“
android:valueTo=“@string/path_remove“
android:interpolator=“@android:interpolator/fast_out_slow_in“
android:valueType=“pathType“ />
Поворачиваем форму
Мы применяем аналогичный подход, чтобы повернуть форму, используя свойство вращения и величины:
android:propertyName=“rotation“
android:valueFrom=“-180“
android:valueTo=“0“
android:duration=“@integer/duration“
android:interpolator=“@android:interpolator/fast_out_slow_in“ />
Анимация обратного (от Убрать до Добавить) работает также, только со значениями анимации вспять.
Наш завершенный Анимационный Вектор вводимого коэффициента выглядит классно, не так ли!
И в заключении…
Несмотря на то, что она просто касается поверхностно самого главного, я надеюсь, что эта статья дала представление о том, как можно создать движение со смыслом в ваших приложениях. Я с нетерпением жду того, чтобы узнать, как я могу подтолкнуть их дальше и улучшить то, как мои проекты выглядят и ощущаются.
Если вам понравилась эта статья, то, пожалуйста, нажмите «Рекомендую»!
Я хотел бы услышать ваши мысли по этому поводу и где вы используете эти анимации - пожалуйста, оставьте отзыв или напишите мне в твиттере!
Начиная с Android 4.4 в арсенале разработчиков появился дополнительный инструмент для создания анимаций - Transitions Framework. Изначально он предназначался для создания анимаций изменения состояния приложения путём манипулирования несколькими View. С выходом Android 5.0 набор доступных для использования анимаций был расширен, чтобы соответствовать представленной тогда же концепции Material Design.
Transitions Framework позволяет быстро и безболезненно создавать различные анимации. Поэтому в процессе работы над iFunny было невозможно пройти мимо этого инструментария. Вниманию читателей предлагается частный случай использования Transitions API - создание анимации перехода между Activity с эффектом «бесшовности».
С визуальной точки зрения представленные в Transitions Framework анимации переходов между Activity можно условно разделить на два типа: обычные анимации и анимации с общим элементом. Концепт анимации с общим элементом продемонстрирован на честно украденном с сайта developer.android.com рис. 1. На нём в роли общих элементов выступают аватар и имя контакта.
Рис. 1. Анимация перехода между Activity с общими элементами
Но никто не любит длинные вступления, поэтому сразу перейдём к рассказу о том, как создавались анимации данного типа в приложении iFunny. В качестве первого примера рассмотрим анимацию, показанную на рис. 2. Для её использования нам потребуется Android версии 5.0 и выше.
Рис. 2. Анимация перехода между Activity на экране аутентификации пользователя
С точки зрения пользователя, здесь нет ничего необычного: один экран, простенькая анимация. Но, как вы уже могли догадаться, «под капотом» - переход между двумя экранами с одним общим элементом.
Первым шагом к созданию подобного перехода является, как ни странно, выбор этого самого элемента и определение его местоположения в вёрстке обеих Activity. После этого в описание каждого View, отображающего выбранный элемент, нужно добавить атрибут android:transitionName, а также назначить им android:id, если таковой отсутствует.
В нашем случае это обычные ImageView следующего вида:
Здесь стоит отметить два важных момента. Во-первых, в обоих ImageView необходимо установить одинаковые transitionName, что логично. Во-вторых, коль скоро мы используем ImageView, то и содержимое у них должно быть одним и тем же, поскольку использование двух отличающихся ресурсов может привести к неожиданным последствиям (как минимум к морганию анимируемого View в начале и конце анимации).
На втором шаге необходимо добавить опции для запускаемой (второй) Activity, сообщающие о том, что при её запуске должна быть запущена анимация.
Примечание. Под «второй» подразумевается запускаемая Activity, переход к которой должен быть осуществлён, а под «первой» - запускающая Activity.
Делается это следующим образом:
Bundle bundle = null;
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
View v = activity.findViewById(R.id.auth_logo);
if (v != null) {
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(activity, v, activity.getString(R.string.email_auth_transition));
bundle = options.toBundle();
}
}
Intent intent = new Intent(activity, SecondActivity.class);
if (bundle == null) {
activity.startActivity(intent);
} else {
activity.startActivity(intent, bundle);
}
В приведённом листинге:
- R.id.auth_logo - ImageView из первой Activity, используемый в анимации;
- activity - первая Activity;
- R.string.email_auth_transition - метка, ранее оставленная в вёрстке обоих ImageView;
- SecondActivity.class - вторая Activity.
На третьем шаге необходимо описать анимацию перехода, т.е. указать путь, проходимый анимируемым View, и трансформацию самого View. Для этого создадим отдельный файл projectName/src/main/res/transitions/email_auth_transition.xml со следующим содержимым:
Немного теории. Тег transitionSet предназначен для описания сразу нескольких трансформаций, применяемых к анимируемому View. Параметр transitionOrdering отвечает за порядок применения этих трансформаций. В нашем случае они применяются одновременно. Существует несколько типов готовых трансформаций, представленных в Transitions Framework. С полным списком можно ознакомиться на этой странице . Мы же остановимся на двух конкретных: changeBounds и changeImageTransform.
Первая предназначена для трансформации размера View. Вторая работает только с ImageView и в связке с первой позволяет изменять не только размер, но и форму ImageView. Использовав данные трансформации, получаем на выходе анимацию изменения размера изображения, представленную на рис. 2. Если не указывать тип движения анимируемого View, то он будет двигаться по кратчайшему пути. Более интересный способ передвижения рассмотрим во втором примере.
Последним шагом создания анимации является её объявление в темах обеих Activity. Для этого отредактируем описание тем следующим образом (или создадим новые в папке projectName/src/main/res/values-v22/theme.xml):
Здесь:
- android:windowActivityTransitions разрешает выполнение анимации перехода;
- android:windowSharedElementEnterTransition указывает на файл с описанием анимации перехода от первой Activity ко второй;
- android:windowSharedElementExitTransition указывает на файл с описанием анимации перехода при возвращении из второй Activity в первую.
Итак, для создания анимации перехода от Activity к Activity необходимо:
- Описать анимации (в нашем случае в xml-файле);
- Добавить эти анимации в xml-описание темы Activity;
- Пометить анимируемый общий элемент (View) в разметке;
- При запуске второй Activity указать в параметрах запуска, что для неё необходимо задействовать анимацию перехода.
Рис. 3. Анимация перехода из комментариев к профилю пользователя
Все шаги по созданию перехода, рассмотренные выше, также подходят для этой анимации. А вот трансформация общего элемента реализована немного иначе. В приведённом ниже листинге описано перемещение общего элемента «по дуге» вместе с изменением его размера.
В чём же сложность второго примера? В первом случае использовалось изображение из ресурсов самого приложения, а тут - картинка загружается из сети. К тому же для комментариев изображение аватара пользователя берётся в более низком разрешении, чем для профиля. Поэтому требуется не только дать второй Activity доступ к изображению, используемому в первой, но и по завершении анимации подгрузить требуемое изображение в более высоком качестве. Так и получается две проблемы.
Для решения первой можно было бы собственноручно закэшировать изображение на диск или же передать его адрес в параметре второй Activity. Однако решение данной проблемы переложили на используемую в приложении библиотеку для загрузки изображений - Glide. При загрузке изображения достаточно просто добавить параметр diskCacheStrategy(DiskCacheStrategy.SOURCE), и оно будет закэшировано самой библиотекой (актуально для Glide версии 3.x). Следовательно, при повторном обращении к данному ресурсу из второй Activity будет использоваться кэшированный файл, что поможет нам избежать моргания анимируемого ImageView.
Вторая проблема также решается достаточно просто. В то время как осуществляется анимация перехода, профиль пользователя вместе с аватаром в более высоком разрешении скачиваются из сети и ожидают её завершения. Как только выполняются оба условия (завершение анимации и завершение загрузки), аватар пользователя обновляется. Добиться такого поведения можно, если использовать специальный Listener, в котором реализованы колбэки, вызываемые при смене статуса анимации. Для этого во Fragment, который принадлежит второй Activity, зададим этот самый Listener:
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
getActivity().getWindow().getSharedElementEnterTransition()
.addListener(mEnterTransitionListener);
}
setAvatar();
}
Здесь происходит следующее:
- С помощью getSharedElementEnterTransition().addListener() задаётся Listener для анимации появления Activity;
- В методе setAvatar() производится попытка загрузки и установки аватара (который уже лежит в кэше).
Private Transition.TransitionListener mEnterTransitionListener =
new Transition.TransitionListener() {
@Override
public void onTransitionStart(Transition transition) {
}
@Override
public void onTransitionEnd(Transition transition) {
onProfileUpdated();
}
@Override
public void onTransitionCancel(Transition transition) {
}
@Override
public void onTransitionPause(Transition transition) {
}
@Override
public void onTransitionResume(Transition transition) {
}
};
В методе onProfileUpdated() мы обновляем содержимое профиля, в т.ч. и аватар.
Стоит отдельно упомянуть случай, когда общий элемент уходит за пределы экрана. Особенность его состоит в том, что, вопреки (а может, и согласно) логике, анимация перехода всё равно будет выполнена и будет смотреться достаточно забавно (рис. 4).
Рис. 4. Анимация возвращения из профиля в комментарии
Чтобы избежать подобного поведения, достаточно в момент ухода общего элемента за пределы экрана выставить ему видимость, отличную от View.VISIBLE.
В целом можно сказать, что Transitions Framework является простым и мощным инструментом для создания анимаций. Он не ограничивается только анимациями перехода между Activity - в статье был рассмотрен лишь частный случай его использования. Также стоит отметить, что помимо предоставляемых трансформаций имеется возможность создавать свои собственные, но это уже совсем другая история, достойная отдельного поста.
P.S. А о том, как придумывались анимации для iFunny, вы можете прочитать .
Теги:
- android
- material design
Обозначение металлических труб. Рассмотрим обозначения наиболее распространенных металлических трубопроводов согласно ГОСТ. Стальные водогазопроводные трубы по ГОСТ В обозначении трубы указывают условны диаметр, длину (при использовании труб мерной длины), толщину стенки. Рассмотрим пример обозначения трубы с диаметром условного прохода 32 мм, толщиной стенки 2,8 мм, без покрытия цинком: Труба 32х2,8 ГОСТ Наличие цинкового покрытия обозначают буквой Ц, которую размещают после слова "Труба".
При необходимости в обозначении трубы указывается отметка о наличии резьбы. Маркировка стальных труб по ГОСТ производится на заводе после изготовления и содержит информацию о размере, марке стали, из которой изготовлена труба, а также товарный знак производителя. Размер букв и цифр клеймления прямо пропорционально зависит от размера изделия и может наноситься несколькими методами.
Самые распространенные – клеймление и водостойкая краска. Виды контроля и их обозначение в маркировке изделий рассмотрены в таблице (Таблица); Следующий пункт «» обозначает толщину стенки в миллиметрах; Четвертое значение указывает длину изделия в миллиметрах от среза до среза, в данном случае это «».
Как расшифровать маркировку стальных труб: диаметр, марка стали и иные показатели по ГОСТу. Условные обозначения, нанесенные на стальную трубу, дают исчерпывающую информацию о продукции.
Маркировка – своеобразный паспорт изделия, из которого становится понятно, кто, где и для каких целей его изготовил. О том, как правильно расшифровать все символы маркировки на трубах, расскажет эта статья.
Примечание. Маркировка труб стальных (и чугунных) регламентируется ГОСТ № от года. В этом документе определены все нюансы нанесения пояснительных надписей, их размеры, расстояния между цифрами и.
Трубы стальные бесшовные холоднодеформированные ГОСТ (Сортамент) Настоящий стандарт распространяется на холоднодеформированные бесшовные трубы общего назначения из углеродистой и легированной стали. Диаметры: 5 - мм. В условных обозначениях труб индекс А или В проставляется перед маркой стали. Трубы изготовляют термически обработанными или без термической обработки.
Концы труб должны быть обрезаны под прямым углом. Способы нанесения маркировки на стальные трубы: стандарты ГОСТ, примеры расшифровки условных обозначений. Прочитав цифры на изделии, специалист может определить размер трубы, ее тип, марку стали, прочность, предприятие-изготовитель и некоторые другие параметры изделия.
Маркировка стальных труб специального назначения содержит дополнительную маркировку. К изделиям специального назначения относятся: Трубы из легированных марок стали. 4. Ссы ЛО чн Ы Е Норм ативно-технические докум енты. Обозначение НТД. на который дана ссылка. Ш с г -80 ГОСТ ю С1 Номер пункта. Изменение № 2 ГОСТ - 91 Трубы стальные элоктросвариые прямош овные.
Сортамент Принято Межгосударственным советом по стандартизации, метрологии и сертификации по пере писке (протокол № 45- от) Зарегистрировано Бюро по стандартам МГС № За принятие изменения проголосовали национальные органы по стандартизации следующих госу дарств: BY, KG, RU, TJ [код ы альфа-2 по МК (ИСО) ].
Продажа и покупка. Трубы стальные обозначение. Трубы стальные электросварные прямошовные. Сортамент. ГОСТ ИПК Издательство с тандартов. Государственный стандарт союза сср. Трубы стальные электросварные пр ямо шов ные. С ортамент. Electrically w elded steel line-weld lubes. Range. ГОСТ Дата введ ения 1. Настоящи й стандарт устана вливает сор тамент стальных электросварных прямошовных труб.
2. Размеры труб должны соответство вать табл. 1. 3. По длине трубы изготовляют: немерной длины Обозначение НТД, на который дана ссылка. Номер пункта. ГОСТ
Categories Post navigation