Движение, основанное на физике, приводится в движение силой. Сила пружины — одна из таких сил, которая направляет интерактивность и движение. Сила пружины обладает следующими свойствами: демпфированием и жесткостью. В анимации на основе пружины значение и скорость рассчитываются на основе силы пружины, приложенной к каждому кадру.
Если вы хотите, чтобы анимация вашего приложения замедлялась только в одном направлении, рассмотрите возможность использования вместо этого анимации движения на основе трения.
Жизненный цикл весенней анимации
В анимации на основе пружины класс 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) }
Ява
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
на получение обратного вызова каждый раз, когда происходит изменение свойства текущего представления. Обратный вызов уведомляет другое представление об обновлении его пружинной позиции на основе изменения, внесенного в свойство текущего представления. Чтобы зарегистрировать прослушиватель, выполните следующие действия:
- Вызовите метод
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) }
Ява
// 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()
и передайте максимальное значение свойства.
Оба метода возвращают анимацию, для которой устанавливается значение.
Примечание. Если вы установили начальное значение и определили диапазон значений анимации, убедитесь, что начальное значение находится в пределах минимального и максимального диапазона значений.
Установить начальную скорость
Начальная скорость определяет скорость, с которой изменяется свойство анимации в начале анимации. Начальная скорость по умолчанию установлена на ноль пикселей в секунду. Вы можете установить скорость либо с помощью скорости сенсорных жестов, либо используя фиксированное значение в качестве начальной скорости. Если вы решите указать фиксированное значение, мы рекомендуем определить значение в dp в секунду, а затем преобразовать его в пиксели в секунду. Определение значения в dp в секунду позволяет скорости не зависеть от плотности и форм-факторов. Дополнительные сведения о преобразовании значения в количество пикселей в секунду см. в разделе Преобразование dp в секунду в количество пикселей в секунду .
Чтобы установить скорость, вызовите метод 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) } }
Ява
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);
Конвертация dp в секунду в пикселей в секунду
Скорость пружины должна быть в пикселях в секунду. Если вы решите указать фиксированное значение в качестве начала скорости, укажите значение в dp в секунду, а затем преобразуйте его в пиксели в секунду. Для преобразования используйте метод applyDimension()
из класса TypedValue
. Обратитесь к следующему примеру кода:
Котлин
val pixelPerSecond: Float = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpPerSecond, resources.displayMetrics)
Ява
float pixelPerSecond = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpPerSecond, getResources().getDisplayMetrics());
Установить свойства пружины
Класс SpringForce
определяет методы получения и установки для каждого свойства пружины, например коэффициента демпфирования и жесткости. Чтобы задать свойства пружины, важно либо получить объект силы пружины, либо создать пользовательскую силу пружины, для которой можно задать свойства. Дополнительную информацию о создании пользовательской силы пружины см. в разделе «Создание пользовательской силы пружины» .
Совет: Используя методы установки, вы можете создать цепочку методов, поскольку все методы установки возвращают объект силы пружины.
Коэффициент демпфирования
Коэффициент демпфирования описывает постепенное уменьшение колебаний пружины. Используя коэффициент затухания, вы можете определить, насколько быстро затухают колебания от одного отскока к другому. Существует четыре различных способа демпфирования пружины:
- Чрезмерное демпфирование возникает, когда коэффициент демпфирования больше единицы. Это позволяет объекту плавно вернуться в исходное положение.
- Критическое демпфирование возникает, когда коэффициент демпфирования равен единице. Это позволяет объекту вернуться в исходное положение в кратчайшие сроки.
- Недостаточное демпфирование происходит, когда коэффициент демпфирования меньше единицы. Он позволяет объекту несколько раз пролетать мимо исходного положения, а затем постепенно достигать исходного положения.
- Незатухание возникает, когда коэффициент демпфирования равен нулю. Это позволяет объекту колебаться вечно.
Чтобы добавить коэффициент демпфирования пружины, выполните следующие действия:
- Вызовите метод
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 … } }
Ява
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 … } }
Ява
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() … } }
Ява
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()
вызывает визуальный переход.