Tween-анимация представляет анимацию различных свойств объекта, при которой система сама расчитывает некоторые промежуточные значения с помощью определенного алгоритма, который называется интерполяцией. В Android алгоритм интерполяции определяется встроенным классом Animation.
От данного класса наследуются классы, которые описывают конкретные типы анимаций, такие как AlphaAnimation (изменение прозрачности), RotateAnimation (анимация вращения), ScaleAnimation (анимация масштабирования), TranslateAnimation (анимация перемещения).
Мы можем определить анимацию как в коде java, так и в файле xml. Для хранения ресурсов анимации в папке res предназначена папка anim. По умолчанию данная папка отсуствует в проекте, поэтому создадим ее. Для этого нажмем правой кнопкой мыши на папку res и в появившемся контекстном меню выберем пункт New -> Android Resource Directory
:Затем в появившемся окне укажем тип ресурсов - anim
Далее добавим в нее новый xml-файл, который назовем common_animation.xml:
Определим в этом файле следующее содержание:
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/linear_interpolator"> <scale android:fromXScale="1.0" android:toXScale="0.5" android:fromYScale="1.0" android:toYScale="0.5" android:pivotX="50%" android:pivotY="50%" android:duration="4500" android:repeatCount="infinite" android:repeatMode="reverse" /> <rotate android:fromDegrees="0.0" android:toDegrees="60.0" android:pivotX="50%" android:pivotY="50%" /> <alpha android:fromAlpha="1.0" android:toAlpha="0.1" android:duration="2250" android:repeatCount="infinite" android:repeatMode="reverse" /> <translate android:fromXDelta="0.0" android:toXDelta="50.0" android:fromYDelta="20.0" android:toYDelta="80.0" android:duration="2250" android:repeatMode="reverse" android:repeatCount="infinite" /> </set>
Здесь задействуются четыре типа анимаций: элемент scale
представляет масштабирование, элемент rotate
- вращение,
элемент alpha
- изменение прозрачности, элемент translate
- перемещение. Если бы мы использовали одну анимацию, то могли бы определить
один корневой элемент по типу анимации. Но так как мы используем набор, то все анимации помещаются в элемент set, который
представляет класс AnimationSet
Все виды анимаций принимают ряд общих свойств. В частности, свойство android:repeatMode, которое указывает на редим выполнения.
Если имеет значение reverse
, то анимация выполняется также и в обратную сторону
Свойство android:repeatCount указывает на количество повторов анимации. Значение infinite
устанавливает
бесконечное число повторов.
Время анимации задается с помощью свойства android:duration
Для всех анимаций также характерно указание начальной и конечной точки трансформации.
Для анимация масштабирования задается начальное масштабирование
по оси х (android:fromXScale
) и по оси y (android:fromYScale
) и конечные значения масштабирования android:toXScale
и android:toYScale
. Например, так как android:fromXScale=1.0, а android:toXScale=0.5, то по ширине будет происходить сжатие на 50%.
Также при масштабировании устанавливаются зачения android:pivotX
и android:pivotY
, которые указывают на центр масшабирования или опорную точку.
Для анимации вращения задается начальное (android:fromDegrees
) и конечное значения поворота (android:toDegrees
).
С помощью свойств android:pivotX
и android:pivotY
также, как и при масштабировании, задается опорная точка вращения.
Для анимации прозрачности задается начальное значение прозрачности (android:fromAlpha
) и финальное значение, устанавливамое при завершении анимации
(android:toAlpha
). Все значения варьируютс в диапазоне от 1.0 (непрозрачный) до 0.0 (полностью прозрачный)
Для перемещения также устанавливаются начальные (android:fromXDelta
и android:fromYDelta
) и конечные значения
(android:toXDelta
и android:toYDelta
)
Для всех анимаций начальные и конечные значения указывают некий диапазон, в котором будут ранжироваться значения. Само вычисление значений на этом промежутке
зависит от конкретного алгоритма. В данном случае в качестве алгоритма устанавливается линейная интерполяция. Для этого у корневого элемента
set
определено свойство android:interpolator="@android:anim/linear_interpolator"
.
Кроме данного значения свойство android:interpolator может принимать еще ряд других: bounce_interpolator, cycle_interpolator и т.д.
Данная анимация будет применяться к элементу ImageView, который определим в файле разметки интерфейса:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" > <ImageView android:id="@+id/animationView" android:layout_width="0dp" android:layout_height="0dp" android:adjustViewBounds="true" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent"/> </androidx.constraintlayout.widget.ConstraintLayout>
Для демонстрации анимации добавим в папку res/drawable какой-нибудь графический файл. В моем случае это файл dubi2.png.
Теперь определим и запустим анимацию в классе MainActivity:
package com.example.animationapp; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.ImageView; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ImageView img = findViewById(R.id.animationView); // определим для ImageView какое-нибудь изображение img.setImageResource(R.drawable.dubi2); // создаем анимацию Animation animation = AnimationUtils.loadAnimation(this, R.anim.common_animation); // запуск анимации img.startAnimation(animation); } }
Сначала определяем анимацию по тому файлу common_animation.xml, который содержит набор анимаций:
Animation animation = AnimationUtils.loadAnimation(this, R.anim.common_animation);
А потом запускаем ее:
img.startAnimation(animation);