Движение, основанное на физических принципах, обусловлено силой. Пружинная сила — одна из таких сил, которая направляет интерактивность и движение. Пружинная сила обладает следующими свойствами: демпфирование и жесткость. В анимации, основанной на пружинной силе, значение и скорость рассчитываются на основе пружинной силы, приложенной к каждому кадру.
Если вы хотите, чтобы анимация в вашем приложении замедлялась только в одном направлении, рассмотрите возможность использования анимации броска на основе трения.
Жизненный цикл весенней анимации
В анимации с использованием пружины класс SpringForce позволяет настраивать жесткость пружины, коэффициент демпфирования и ее конечное положение. Как только начинается анимация, сила пружины обновляет значение анимации и скорость в каждом кадре. Анимация продолжается до тех пор, пока сила пружины не достигнет равновесия.
Например, если вы перетаскиваете значок приложения по экрану, а затем отпускаете его, убрав палец с значка, значок вернется на свое исходное место под действием невидимой, но знакомой силы.
На рисунке 1 показан аналогичный пружинный эффект. Знак плюс (+) в центре круга указывает на силу, приложенную при касании.

Создайте пружинную анимацию
Общие шаги по созданию пружинной анимации для вашего приложения следующие:
- Добавьте библиотеку поддержки. Для использования классов анимации Spring необходимо добавить библиотеку поддержки в ваш проект.
- Создание пружинной анимации: Первым шагом является создание экземпляра класса
SpringAnimationи установка параметров поведения движения. - (Необязательно) Регистрация слушателей: Зарегистрируйте слушателей для отслеживания изменений жизненного цикла анимации и обновлений значений анимации.
Примечание: Слушатель обновления следует регистрировать только в том случае, если вам необходимо обновлять значения анимации покадрово. Слушатель обновления предотвращает потенциальное выполнение анимации в отдельном потоке.
- (Необязательно) Удалить слушатели: Удалить слушатели, которые больше не используются.
- (Необязательно) Установите начальное значение: Настройте начальное значение анимации.
- (Необязательно) Задайте диапазон значений: установите диапазон значений анимации, чтобы ограничить значения минимальным и максимальным диапазоном.
- (Необязательно) Установка начальной скорости: Задайте начальную скорость анимации.
- (Необязательно) Настройка свойств пружины: задайте коэффициент демпфирования и жесткость пружины.
- (Необязательно) Создайте пользовательскую пружину: Создайте пользовательскую пружину, если вы не собираетесь использовать пружину по умолчанию или хотите использовать общую пружину на протяжении всей анимации.
- Начать анимацию: Запустить пружинную анимацию.
- (Необязательно) Отмена анимации: Отмените анимацию в случае, если пользователь внезапно выйдет из приложения или изображение станет невидимым.
В следующих разделах подробно рассматриваются общие этапы создания пружинной анимации.
Добавить библиотеку поддержки
Для использования библиотеки поддержки, основанной на физических принципах, необходимо добавить её в проект следующим образом:
- Откройте файл
build.gradleдля вашего модуля приложения. Добавьте библиотеку поддержки в раздел
dependencies.Классный
dependencies { def dynamicanimation_version = '1.0.0' implementation "androidx.dynamicanimation:dynamicanimation:$dynamicanimation_version" }
Котлин
dependencies { val dynamicanimation_version = "1.0.0" implementation("androidx.dynamicanimation:dynamicanimation:$dynamicanimation_version") }
Чтобы просмотреть текущие версии этой библиотеки, ознакомьтесь с информацией о Dynamicanimation на странице версий .
Создайте весеннюю анимацию
Класс SpringAnimation позволяет создать пружинную анимацию для объекта. Для создания пружинной анимации необходимо создать экземпляр класса SpringAnimation и указать объект, свойство объекта, которое вы хотите анимировать, и, при необходимости, конечное положение пружины, в котором вы хотите завершить анимацию.
Примечание: При создании анимации пружины конечное положение пружины является необязательным. Однако его необходимо определить до начала анимации.
Котлин
val springAnim = findViewById<View>(R.id.imageView).let { img -> // Setting up a spring animation to animate the view’s translationY property with the final // spring position at 0. SpringAnimation(img, DynamicAnimation.TRANSLATION_Y, 0f) }
Java
final View img = findViewById(R.id.imageView); // Setting up a spring animation to animate the view’s translationY property with the final // spring position at 0. final SpringAnimation springAnim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y, 0);
Пружинная анимация позволяет оживлять элементы на экране, изменяя фактические свойства объектов представления. В системе доступны следующие представления:
-
ALPHA: Отображает альфа-канал прозрачности элемента. По умолчанию значение равно 1 (непрозрачный), а значение 0 означает полную прозрачность (не виден). -
TRANSLATION_X,TRANSLATION_YиTRANSLATION_Z: Эти свойства определяют положение вида относительно его левой координаты, верхней координаты и высоты, которые задаются контейнером макета.-
TRANSLATION_Xописывает левую координату. -
TRANSLATION_Yописывает верхнюю координату. -
TRANSLATION_Zописывает глубину обзора относительно его высоты.
-
-
ROTATION,ROTATION_XиROTATION_Y: Эти свойства управляют вращением в 2D (свойствоrotation) и 3D вокруг точки опоры. -
SCROLL_XиSCROLL_Y: Эти свойства указывают смещение прокрутки относительно левого и верхнего края страницы в пикселях. Они также указывают положение страницы в терминах степени прокрутки. -
SCALE_XиSCALE_Y: Эти свойства управляют масштабированием представления в 2D-пространстве относительно его опорной точки. -
X,YиZ: это основные вспомогательные свойства, описывающие конечное местоположение представления в его контейнере.-
X— это сумма значения слева иTRANSLATION_X. -
Yпредставляет собой сумму максимального значения иTRANSLATION_Y. -
Zпредставляет собой сумму значения высоты иTRANSLATION_Z.
-
Зарегистрируйте слушателей
Класс DynamicAnimation предоставляет два слушателя: OnAnimationUpdateListener и OnAnimationEndListener . Эти слушатели отслеживают обновления анимации, например, изменение значения анимации и завершение анимации.
OnAnimationUpdateListener
Если вы хотите анимировать несколько представлений для создания цепочки анимаций, вы можете настроить OnAnimationUpdateListener таким образом, чтобы он получал обратный вызов каждый раз, когда изменяется свойство текущего представления. Обратный вызов уведомляет другое представление об обновлении его пружинного положения в зависимости от изменения свойства текущего представления. Для регистрации слушателя выполните следующие шаги:
- Вызовите метод
addUpdateListener()и прикрепите слушатель к анимации.Примечание: Необходимо зарегистрировать обработчик обновления до начала анимации. Однако регистрировать обработчик обновления следует только в том случае, если вам требуется обновление значений анимации для каждого кадра. Обработчик обновления предотвращает потенциальное выполнение анимации в отдельном потоке.
- Переопределите метод
onAnimationUpdate(), чтобы уведомить вызывающую сторону об изменении текущего объекта. Следующий пример кода иллюстрирует общее использованиеOnAnimationUpdateListener.
Котлин
// Setting up a spring animation to animate the view1 and view2 translationX and translationY properties val (anim1X, anim1Y) = findViewById<View>(R.id.view1).let { view1 -> SpringAnimation(view1, DynamicAnimation.TRANSLATION_X) to SpringAnimation(view1, DynamicAnimation.TRANSLATION_Y) } val (anim2X, anim2Y) = findViewById<View>(R.id.view2).let { view2 -> SpringAnimation(view2, DynamicAnimation.TRANSLATION_X) to SpringAnimation(view2, DynamicAnimation.TRANSLATION_Y) } // Registering the update listener anim1X.addUpdateListener { _, value, _ -> // Overriding the method to notify view2 about the change in the view1’s property. anim2X.animateToFinalPosition(value) } anim1Y.addUpdateListener { _, value, _ -> anim2Y.animateToFinalPosition(value) }
Java
// Creating two views to demonstrate the registration of the update listener. final View view1 = findViewById(R.id.view1); final View view2 = findViewById(R.id.view2); // Setting up a spring animation to animate the view1 and view2 translationX and translationY properties final SpringAnimation anim1X = new SpringAnimation(view1, DynamicAnimation.TRANSLATION_X); final SpringAnimation anim1Y = new SpringAnimation(view1, DynamicAnimation.TRANSLATION_Y); final SpringAnimation anim2X = new SpringAnimation(view2, DynamicAnimation.TRANSLATION_X); final SpringAnimation anim2Y = new SpringAnimation(view2, DynamicAnimation.TRANSLATION_Y); // Registering the update listener anim1X.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() { // Overriding the method to notify view2 about the change in the view1’s property. @Override public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float value, float velocity) { anim2X.animateToFinalPosition(value); } }); anim1Y.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() { @Override public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float value, float velocity) { anim2Y.animateToFinalPosition(value); } });
OnAnimationEndListener
OnAnimationEndListener уведомляет об окончании анимации. Вы можете настроить слушатель таким образом, чтобы он получал обратный вызов всякий раз, когда анимация достигает равновесия или отменяется. Для регистрации слушателя выполните следующие шаги:
- Вызовите метод
addEndListener()и прикрепите слушатель к анимации. - Переопределите метод
onAnimationEnd(), чтобы получать уведомления всякий раз, когда анимация достигает состояния равновесия или отменяется.
Удалить слушателей
Чтобы прекратить получение обратных вызовов обновления анимации и завершения анимации, вызовите методы removeUpdateListener() и removeEndListener() соответственно.
Установить начальное значение анимации
Чтобы задать начальное значение анимации, вызовите метод setStartValue() и передайте ему начальное значение анимации. Если вы не зададите начальное значение, анимация будет использовать текущее значение свойства объекта в качестве начального значения.
Задать диапазон значений анимации
Вы можете установить минимальное и максимальное значения анимации, если хотите ограничить значение свойства определенным диапазоном. Это также помогает контролировать диапазон, если вы анимируете свойства, имеющие внутренний диапазон, например, альфа-канал (от 0 до 1).
- Чтобы установить минимальное значение, вызовите метод
setMinValue()и передайте минимальное значение свойства. - Чтобы установить максимальное значение, вызовите метод
setMaxValue()и передайте ему максимальное значение свойства.
Оба метода возвращают анимацию, для которой устанавливается значение.
Примечание: Если вы задали начальное значение и определили диапазон значений анимации, убедитесь, что начальное значение находится в пределах минимального и максимального диапазонов значений.
Установить начальную скорость
Начальная скорость определяет скорость изменения свойства анимации в начале анимации. По умолчанию начальная скорость равна нулю пикселей в секунду. Вы можете установить скорость либо с помощью скорости сенсорных жестов, либо задав фиксированное значение в качестве начальной скорости. Если вы решите задать фиксированное значение, рекомендуется указать его в децибелах в секунду, а затем преобразовать в пиксели в секунду. Определение значения в децибелах в секунду позволяет сделать скорость независимой от плотности и форм-фактора. Для получения дополнительной информации о преобразовании значения в пиксели в секунду см. раздел «Преобразование децибелов в секунду в пиксели в секунду» .
Чтобы задать скорость, вызовите метод setStartVelocity() и передайте значение скорости в пикселях в секунду. Метод возвращает объект силы пружины, для которой задана скорость.
Примечание: Для получения и вычисления скорости сенсорных жестов используйте методы GestureDetector.OnGestureListener или VelocityTracker .
Котлин
findViewById<View>(R.id.imageView).also { img -> SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply { … // Compute velocity in the unit pixel/second vt.computeCurrentVelocity(1000) val velocity = vt.yVelocity setStartVelocity(velocity) } }
Java
final View img = findViewById(R.id.imageView); final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y); … // Compute velocity in the unit pixel/second vt.computeCurrentVelocity(1000); float velocity = vt.getYVelocity(); anim.setStartVelocity(velocity);
Преобразование диоптрий в секунду в пиксели в секунду
Скорость пружины должна быть выражена в пикселях в секунду. Если вы решили задать фиксированное значение в качестве начальной скорости, укажите его в децибелах в секунду, а затем преобразуйте в пиксели в секунду. Для преобразования используйте метод applyDimension() из класса TypedValue . См. следующий пример кода:
Котлин
val pixelPerSecond: Float = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpPerSecond, resources.displayMetrics)
Java
float pixelPerSecond = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpPerSecond, getResources().getDisplayMetrics());
Задать свойства пружины
Класс SpringForce определяет методы получения (getter) и установки (setter) для каждого из свойств пружины, таких как коэффициент демпфирования и жесткость. Для установки свойств пружины важно либо получить объект силы пружины, либо создать собственную силу пружины, для которой можно задать свойства. Дополнительную информацию о создании собственной силы пружины см. в разделе «Создание собственной силы пружины» .
Совет: При использовании методов-сеттеров вы можете создать цепочку методов, поскольку все методы-сеттеры возвращают объект силы пружины.
Коэффициент демпфирования
Коэффициент затухания описывает постепенное уменьшение колебаний пружины. Используя коэффициент затухания, можно определить, насколько быстро затухают колебания от одного отскока к другому. Существует четыре различных способа затухания пружины:
- Передемпфирование происходит, когда коэффициент демпфирования превышает единицу. Оно позволяет объекту плавно вернуться в положение покоя.
- Критическое затухание происходит, когда коэффициент затухания равен единице. Оно позволяет объекту вернуться в положение покоя за кратчайшее время.
- Недостаточное демпфирование возникает, когда коэффициент демпфирования меньше единицы. Это приводит к многократному прохождению объектом положения покоя, после чего он постепенно возвращается в это положение.
- Незатухающий режим возникает, когда коэффициент затухания равен нулю. В этом случае объект может колебаться бесконечно.
Для увеличения коэффициента демпфирования пружины выполните следующие действия:
- Вызовите метод
getSpring(), чтобы получить значение пружины и добавить коэффициент демпфирования. - Вызовите метод
setDampingRatio()и передайте ему коэффициент демпфирования, который вы хотите добавить к пружине. Метод возвращает объект силы пружины, для которой установлен коэффициент демпфирования.Примечание: Коэффициент демпфирования должен быть неотрицательным числом. Если установить коэффициент демпфирования равным нулю, пружина никогда не достигнет положения покоя. Другими словами, она будет колебаться бесконечно.
В системе доступны следующие константы коэффициента демпфирования:
-
DAMPING_RATIO_HIGH_BOUNCY -
DAMPING_RATIO_MEDIUM_BOUNCY -
DAMPING_RATIO_LOW_BOUNCY -
DAMPING_RATIO_NO_BOUNCY
Рисунок 2: Высокий отскок
Рисунок 3: Средний отскок
Рисунок 4: Низкий отскок
Рисунок 5: Отскок отсутствует
Коэффициент демпфирования по умолчанию установлен на DAMPING_RATIO_MEDIUM_BOUNCY .
Котлин
findViewById<View>(R.id.imageView).also { img -> SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply { … // Setting the damping ratio to create a low bouncing effect. spring.dampingRatio = SpringForce.DAMPING_RATIO_LOW_BOUNCY … } }
Java
final View img = findViewById(R.id.imageView); final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y); … // Setting the damping ratio to create a low bouncing effect. anim.getSpring().setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY); …
Жесткость
Жесткость определяет постоянную пружины, которая измеряет силу пружины. Жесткая пружина прикладывает большую силу к прикрепленному объекту, когда пружина находится не в состоянии покоя. Чтобы увеличить жесткость пружины, выполните следующие шаги:
- Вызовите метод
getSpring(), чтобы получить пружину и добавить жесткость. - Вызовите метод
setStiffness()и передайте ему значение жесткости, которое вы хотите добавить к пружине. Метод возвращает объект силы пружины, для которой задана жесткость.Примечание: Жесткость должна быть положительным числом.
В системе доступны следующие константы жесткости:
Рисунок 6: Высокая жесткость
Рисунок 7: Средняя жесткость
Рисунок 8: Низкая жесткость
Рисунок 9: Очень низкая жесткость
По умолчанию жесткость установлена на STIFFNESS_MEDIUM .
Котлин
findViewById<View>(R.id.imageView).also { img -> SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply { … // Setting the spring with a low stiffness. spring.stiffness = SpringForce.STIFFNESS_LOW … } }
Java
final View img = findViewById(R.id.imageView); final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y); … // Setting the spring with a low stiffness. anim.getSpring().setStiffness(SpringForce.STIFFNESS_LOW); …
Создайте пользовательскую силу пружины
В качестве альтернативы использованию силы пружины по умолчанию можно создать собственную силу пружины. Пользовательская сила пружины позволяет использовать один и тот же экземпляр силы пружины в нескольких анимациях пружины. После создания силы пружины можно задать такие свойства, как коэффициент демпфирования и жесткость.
- Создайте объект
SpringForce.SpringForce force = new SpringForce(); - Назначайте свойства, вызывая соответствующие методы. Вы также можете создать цепочку методов.
force.setDampingRatio(DAMPING_RATIO_LOW_BOUNCY).setStiffness(STIFFNESS_LOW); - Вызовите метод
setSpring(), чтобы установить пружину для анимации.setSpring(force);
Начало анимации
Запустить пружинную анимацию можно двумя способами: вызвав метод ` start() или метод ` animateToFinalPosition() . Оба метода необходимо вызывать в основном потоке.
Метод animateToFinalPosition() выполняет две задачи:
- Устанавливает конечное положение пружины.
- Запускает анимацию, если она еще не началась.
Поскольку этот метод обновляет конечное положение пружины и запускает анимацию при необходимости, вы можете вызвать его в любое время, чтобы изменить ход анимации. Например, в цепочке пружинной анимации анимация одного представления зависит от другого. Для такой анимации удобнее использовать метод animateToFinalPosition() . Используя этот метод в цепочке пружинной анимации, вам не нужно беспокоиться о том, выполняется ли в данный момент анимация, которую вы хотите обновить.
На рисунке 10 показана анимация с использованием пружин, где анимация одного элемента зависит от анимации другого элемента.

Для использования метода animateToFinalPosition() вызовите метод animateToFinalPosition() и передайте ему исходное положение пружины. Вы также можете установить исходное положение пружины, вызвав метод setFinalPosition() .
Метод ` start() не устанавливает значение свойства равным начальному значению немедленно. Значение свойства изменяется при каждом импульсе анимации, который происходит до прохода отрисовки. В результате изменения отражаются в следующем кадре, как если бы значения устанавливались немедленно.
Котлин
findViewById<View>(R.id.imageView).also { img -> SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply { … // Starting the animation start() … } }
Java
final View img = findViewById(R.id.imageView); final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y); … // Starting the animation anim.start(); …
Отменить анимацию
Вы можете отменить анимацию или перейти к её завершению. Идеальная ситуация, когда вам нужно отменить анимацию или перейти к её завершению, — это когда взаимодействие с пользователем требует немедленного прекращения анимации. Чаще всего это происходит, когда пользователь резко выходит из приложения или область просмотра становится невидимой.
Для завершения анимации можно использовать два метода. Метод cancel() завершает анимацию на текущем значении. Метод skipToEnd() пропускает анимацию до конечного значения, а затем завершает её.
Прежде чем завершить анимацию, важно сначала проверить состояние пружины. Если она не затухает, анимация никогда не сможет достичь положения покоя. Чтобы проверить состояние пружины, вызовите метод canSkipToEnd() . Если пружина затухает, метод возвращает true , в противном случае false .
Зная состояние пружины, вы можете завершить анимацию, используя либо метод skipToEnd() , либо метод cancel() . Метод cancel() должен вызываться только в основном потоке.
Примечание: Как правило, метод skipToEnd() вызывает визуальный скачок.
