Добавление анимации на основе физики в Android приложения
() translation by (you can also view the original English article)
Анимации, которые кажутся подвижными и реалистичными, как правило, делают пользовательские интерфейсы более привлекательными. Неудивительно, что 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
:
1 |
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
, отображающий значок ic_sentiment_neutral_black_56dp и виджет Button
, который пользователи могут нажать, чтобы вызвать анимацию fling. Если вы разместите их внутри виджета RelativeLayout
, ваш XML-файл макета будет выглядеть так:
1 |
<?xml version="1.0" encoding="utf-8"?>
|
2 |
<RelativeLayout
|
3 |
xmlns:android="https://schemas.android.com/apk/res/android" |
4 |
xmlns:tools="http://schemas.android.com/tools" |
5 |
android:layout_width="match_parent" |
6 |
android:layout_height="match_parent" |
7 |
android:layout_margin="16dp"> |
8 |
|
9 |
<ImageView
|
10 |
android:layout_width="wrap_content" |
11 |
android:layout_height="wrap_content" |
12 |
android:src="@drawable/ic_sentiment_neutral_black_56dp" |
13 |
android:id="@+id/emoji" |
14 |
android:layout_centerInParent="true" |
15 |
/>
|
16 |
|
17 |
<Button
|
18 |
android:layout_width="wrap_content" |
19 |
android:layout_height="wrap_content" |
20 |
android:text="Fling" |
21 |
android:id="@+id/flinger" |
22 |
android:layout_alignParentTop="true" |
23 |
android:layout_alignParentLeft="true" |
24 |
android:onClick="flingIt" /> |
25 |
|
26 |
</RelativeLayout>
|
В приведенном выше коде вы увидите, что виджет Button
имеет атрибут onClick
. Нажав на значок с красным индикатором, который Android Studio покажет рядом с этим, вы можете вызвать обработчик события по клику внутри вашего класса Activity
:
1 |
public void flingIt(View view) { |
2 |
// more code here
|
3 |
}
|
Теперь вы можете создать новый экземпляр класса FlingAnimation
, используя его конструктор, который ожидает объект View
и имя свойства анимирования. Динамическая анимация поддерживает несколько анимационных свойств, таких как масштабирование/scale, трансляция/translation, вращение/rotation и альфа/alpha.
В следующем коде показано, как создать экземпляр FlingAnimation
, который может анимировать координату-Х ImageView
нашего макета:
1 |
// Get a reference to the view
|
2 |
ImageView emoji = (ImageView)findViewById(R.id.emoji); |
3 |
|
4 |
// Pass it to the constructor
|
5 |
FlingAnimation flingAnimation |
6 |
= new FlingAnimation(emoji, DynamicAnimation.X); |
По умолчанию экземпляр FlingAnimation
настроен на использование 0 пикселей в секунду в качестве начальной скорости. Это означает, что анимация остановится, как только она начнется. Чтобы имитировать реалистичный запуск движения, вы всегда должны помнить о вызове метода setStartVelocity()
и передать ему большое значение.
Кроме того, вы должны понимать, что без трения анимация не остановится. Поэтому вы также должны вызвать метод setFriction()
и передать ему небольшое число.
Следующий код настраивает экземпляр FlingAnimation
таким образом, что ImageView
не выходит за границы экрана пользователя:
1 |
flingAnimation.setStartVelocity(500f); |
2 |
flingAnimation.setFriction(0.5f); |
На этом этапе вы можете просто вызвать метод start()
для запуска анимации.
1 |
flingAnimation.start(); |
Если вы сейчас запустите приложение и нажмёте кнопку, вы сможете увидеть анимацию fling.

Стоит отметить, что вы не указываете продолжительность или конечное значение при создании анимации на основе физики — анимация автоматически останавливается, когда она осознает, что её целевой объект не показывает никаких видимых движений на экране пользователя.
3. Имитация пружины — Springs
Динамическая анимация позволяет легко добавить движение пружины в анимацию. Другими словами, это может помочь вам создать анимацию, которая заставит ваши виджеты отскакивать, растягиваться и сплющиваться такими образами, которые кажутся естественными.
Чтобы всё было просто, давайте теперь повторно используем ImageView
нашего макета и применим к нему анимацию с эффектом пружинки. Однако, чтобы позволить пользователю запустить анимацию, вам нужно добавить в макет ещё один виджет Button
.
1 |
<Button
|
2 |
android:layout_width="wrap_content" |
3 |
android:layout_height="wrap_content" |
4 |
android:text="Bounce" |
5 |
android:layout_alignParentTop="true" |
6 |
android:layout_alignParentRight="true" |
7 |
android:onClick="bounce" /> |
Чтобы создать анимацию на основе спружинивания, вы должны использовать класс SpringAnimation
. Его конструктор тоже ожидает объект View
и анимационное свойство. Следующий код создает экземпляр SpringAnimation
, настроенный для анимации координаты Х для ImageView
:
1 |
// Get a reference to the view
|
2 |
final ImageView emoji = (ImageView)findViewById(R.id.emoji); |
3 |
|
4 |
// Pass it to the constructor
|
5 |
SpringAnimation springAnimation |
6 |
= new SpringAnimation(emoji, DynamicAnimation.X); |
Чтобы управлять поведением анимации на основе пружинки, вам понадобится spring. Вы можете создать его с помощью класса SpringForce
, который позволяет вам указать положение покоя качания, коэффициент затухания и жёсткость. Вы можете думать о коэффициенте затухания как о константе, которая, как и трение, несёт ответственность за замедление анимации до её остановки. С другой стороны, жёсткость определяет, сколько силы требуется для растягивания пружины.
Если всё это звучит слишком сложно, хорошей новостью является то, что класс SpringForce
предлагает несколько общеназванных констант, которые вы можете использовать для быстрой настройки пружины. Например, следующий код создает пружину, которая и очень упругая и очень гибкая:
1 |
SpringForce springForce = new SpringForce(); |
2 |
springForce.setFinalPosition(emoji.getX()); |
3 |
springForce.setDampingRatio(SpringForce.DAMPING_RATIO_HIGH_BOUNCY); |
4 |
springForce.setStiffness(SpringForce.STIFFNESS_LOW); |
В приведенном выше коде вы можете видеть, что мы установили значение конечного положения покоя пружины на начальную координату X ImageView
. С такой конфигурацией, вы можете представить, что ImageView
привязан к жесткой невидимой резиновой ленте, которая быстро тянет ImageView
обратно в исходное положение при каждом перемещении.
Теперь вы можете связать пружину с экземпляром SpringAnimation
, используя метод setSpring()
.
1 |
springAnimation.setSpring(springForce); |
Наконец, перед началом анимации вы должны убедиться, что вы придаёте ему большую начальную скорость, используя метод setStartVelocity()
.
1 |
springAnimation.setStartVelocity(2000f); |
2 |
springAnimation.start(); |
Если вы запустите приложение сейчас, вы увидите что-то вроде этого:

4. Прослушивание событий анимации
Анимация, созданная с использованием библиотеки динамической анимации, всегда должна запускаться из пользовательского интерфейса. Вы также можете быть уверены, что он начнется, как только вы вызовете метод start()
. Однако она выполняется асинхронно. Поэтому, если вы хотите, чтобы вас уведомляли, когда она заканчивается, вы должны прикрепить к нему объект OnAnimationEndListener
с помощью метода addEndListener()
.
Чтобы увидеть слушателя в действии, давайте изменим значок Material для начала и окончания анимации, отображаемый ImageView
, каждый раз при пружинной анимации, которую мы создали на предыдущем шаге. Я предлагаю вам использовать значок ic_sentiment_very_satisfied_black_56dp при запуске анимации и значок ic_sentiment_neutral_black_56dp по окончании. В следующем коде показано, как:
1 |
// Change icon before animation starts
|
2 |
emoji.setImageResource( |
3 |
R.drawable.ic_sentiment_very_satisfied_black_56dp); |
4 |
|
5 |
// Start animation
|
6 |
springAnimation.start(); |
7 |
|
8 |
springAnimation.addEndListener( |
9 |
new DynamicAnimation.OnAnimationEndListener() { |
10 |
@Override
|
11 |
public void onAnimationEnd(DynamicAnimation animation, |
12 |
boolean canceled, |
13 |
float value, float velocity) { |
14 |
// Change icon after animation ends
|
15 |
emoji.setImageResource( |
16 |
R.drawable.ic_sentiment_neutral_black_56dp); |
17 |
}
|
18 |
});
|
С приведенным выше кодом анимация будет выглядеть так:

5. Анимация нескольких свойств
Конструкторы классов FlingAnimation
и SpringAnimation
могут принимать только одно анимационное свойство. Если вы хотите одновременно анимировать несколько свойств, вы можете создать несколько экземпляров классов, которые могут стать громоздкими или создать новое настраиваемое свойство, которое кратко отразит все ваши желаемые свойства.
Чтобы создать настраиваемое свойство анимирования, вы должны создать подкласс класса FloatPropertyCompat
, который имеет два абстрактных метода: setValue()
и getValue()
. Как вы могли догадаться, вы можете обновить значения всех желаемых анимационных свойств внутри метода setValue()
. Однако в методе getValue()
необходимо вернуть только текущее значение какого-либо одного свойства. Из-за этого ограничения обычно вам нужно убедиться, что значения укороченных свойств не полностью независимы друг от друга.
Например, следующий код показывает вам, как создать настраиваемое свойство под названием scale
, которое может равномерно анимировать свойства SCALE_X
и SCALE_Y
виджета:
1 |
FloatPropertyCompat<View> scale = |
2 |
new FloatPropertyCompat<View>("scale") { |
3 |
@Override
|
4 |
public float getValue(View view) { |
5 |
// return the value of any one property
|
6 |
return view.getScaleX(); |
7 |
}
|
8 |
|
9 |
@Override
|
10 |
public void setValue(View view, float value) { |
11 |
// Apply the same value to two properties
|
12 |
view.setScaleX(value); |
13 |
view.setScaleY(value); |
14 |
}
|
15 |
};
|
Теперь, когда наше свойство готово, вы можете использовать его, как и любое другое анимационное свойство. В следующем коде показано, как создать с ним объект SpringAnimation
:
1 |
SpringAnimation stretchAnimation = |
2 |
new SpringAnimation(emoji, scale); |
При создании анимации, использующей настраиваемое свойство, неплохо также вызвать метод setMinimumVisibleChange()
и передать ему многозначительное значение, чтобы убедиться, что анимация не потребляет слишком много ЦП. Для нашей анимации, которая масштабирует виджет, вы можете использовать следующий код:
1 |
stretchAnimation.setMinimumVisibleChange( |
2 |
DynamicAnimation.MIN_VISIBLE_CHANGE_SCALE); |
Вот как выглядит анимация настраиваемого свойства:

Заключение
Теперь вы знаете основы работы с Dynamic Animation. С помощью методов, которые вы узнали в этом уроке, вы можете создать убедительные анимации на основе физики за считанные минуты, даже если у вас мало знаний о Ньютоновской физике.
Чтобы узнать больше о динамической анимации, обратитесь к официальной документации. В то же время ознакомьтесь с некоторыми другими нашими недавними статьями о разработке приложений для Android!
- Android SDKCreate an Intelligent App With Google Cloud Speech and Natural Language APIsAshraff Hathibelagal
- AndroidEnsure High-Quality Android Code With Static Analysis ToolsChike Mgbemena
- Android SDKServerless Apps With Firebase Cloud FunctionsChike Mgbemena
- AndroidHow to Solve Android’s 13 Most Common Error MessagesJessica Thornsby