Как переместить представление с анимацией

Попробуйте Compose
Jetpack Compose – это рекомендуемый набор инструментов для создания пользовательского интерфейса в Android. Узнайте, как использовать анимацию в Compose.

Объекты на экране часто нужно перемещать в результате взаимодействия с пользователем или фоновой обработки. Вместо того чтобы сразу обновлять положение объекта, из-за чего он будет мигать, перемещаясь из одной области в другую, используйте анимацию, чтобы переместить его из начального положения в конечное.

Один из способов изменить положение объектов на экране – использовать ObjectAnimator. Вы указываете конечную позицию, в которой должен оказаться объект, а также длительность анимации. Вы также можете использовать интерполяторы времени, чтобы управлять ускорением или замедлением анимации.

Как изменить положение представления с помощью ObjectAnimator

API ObjectAnimator позволяет изменять свойства представления с заданной продолжительностью. Он содержит статические методы для создания экземпляров ObjectAnimator в зависимости от того, какой тип атрибута вы анимируете. Чтобы изменить положение представлений на экране, используйте атрибуты translationX и translationY.

Вот пример ObjectAnimator, который перемещает область просмотра в положение на расстоянии 100 пикселей от левого края экрана за 2 секунды:

Kotlin

ObjectAnimator.ofFloat(view, "translationX", 100f).apply {
    duration = 2000
    start()
}

Java

ObjectAnimator animation = ObjectAnimator.ofFloat(view, "translationX", 100f);
animation.setDuration(2000);
animation.start();

В этом примере используется метод ObjectAnimator.ofFloat(), поскольку значения сдвига должны быть числами с плавающей запятой. Первый параметр – это представление, которое вы хотите анимировать. Второй параметр – это свойство, которое вы анимируете. Поскольку представление должно перемещаться по горизонтали, используется свойство translationX. Последний параметр – это конечное значение анимации. В этом примере значение 100 указывает на позицию, которая находится на расстоянии 100 пикселей от левого края экрана.

Следующий метод определяет длительность анимации в миллисекундах. В этом примере анимация длится две секунды (2000 миллисекунд).

Последний метод запускает анимацию, которая обновляет положение представления на экране.

Подробнее о том, как использовать ObjectAnimator, рассказывается в статье Как создавать анимацию с помощью ObjectAnimator.

Как добавить криволинейное движение

Хотя использовать ObjectAnimator удобно, по умолчанию он перемещает вид по прямой линии между начальной и конечной точками. В Material Design кривые используются для пространственного перемещения объектов на экране и синхронизации анимации. Использование криволинейного движения придает вашему приложению более материальный вид, делая ваши анимации более интересными.

Выбирайте свой путь

Класс ObjectAnimator содержит конструкторы, позволяющие анимировать координаты с помощью двух или более свойств одновременно, а также пути. Например, в следующем аниматоре используется объект Path для анимации свойств X и Y представления:

Kotlin

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    val path = Path().apply {
        arcTo(0f, 0f, 1000f, 1000f, 270f, -180f, true)
    }
    val animator = ObjectAnimator.ofFloat(view, View.X, View.Y, path).apply {
        duration = 2000
        start()
    }
} else {
    // Create animator without using curved path
}

Java

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  Path path = new Path();
  path.arcTo(0f, 0f, 1000f, 1000f, 270f, -180f, true);
  ObjectAnimator animator = ObjectAnimator.ofFloat(view, View.X, View.Y, path);
  animator.setDuration(2000);
  animator.start();
} else {
  // Create animator without using curved path
}

Вот как выглядит анимация дуги:

Рисунок 1. Анимация криволинейного пути.

Interpolator – это реализация кривой плавности. Дополнительную информацию о концепции кривых плавности можно найти в документации по Material Design. Interpolator определяет, как рассчитываются определенные значения в анимации в зависимости от времени. В системе есть XML-ресурсы для трех основных кривых в спецификации Material Design:

  • @interpolator/fast_out_linear_in.xml
  • @interpolator/fast_out_slow_in.xml
  • @interpolator/linear_out_slow_in.xml

Используйте PathInterpolator

Класс PathInterpolator – это интерполятор, представленный в Android 5.0 (API 21). Она основана на кривой Безье или объекте Path. В примерах для Android в документации по смягчению в Material Design используется PathInterpolator.

PathInterpolator имеет конструкторы, основанные на разных типах кривых Безье. Все кривые Безье имеют начальную и конечную точки, зафиксированные в (0,0) и (1,1) соответственно. Другие аргументы конструктора зависят от типа создаваемой кривой Безье.

Например, для квадратичной кривой Безье нужны только координаты X и Y одной контрольной точки:

Kotlin

val myInterpolator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    PathInterpolator(0.67f, 0.33f)
} else {
    LinearInterpolator()
}

Java

Interpolator myInterpolator = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  myInterpolator = new PathInterpolator(0.67f, 0.33f);
} else {
  myInterpolator = new LinearInterpolator();
}

Это создает кривую замедления, которая начинается быстро и замедляется по мере приближения к концу.

Конструктор кубической кривой Безье также имеет фиксированные начальную и конечную точки, но требует двух контрольных точек:

Kotlin

val myInterpolator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    PathInterpolator(0.5f, 0.7f, 0.1f, 1.0f)
} else {
    LinearInterpolator()
}

Java

Interpolator myInterpolator = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  myInterpolator = new PathInterpolator(0.5f, 0.7f, 0.1f, 1.0f);
} else {
  myInterpolator = new LinearInterpolator();
}

Это реализация кривой замедления emphasized decelerate из Material Design.

Для более точного управления можно использовать произвольное значение Path:

Kotlin

val myInterpolator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  val path = Path().apply {
    moveTo(0.0f, 0.0f)
    cubicTo(0.5f, 0.7f, 0.1f, 1.0f, 1.0f, 1.0f)
  }
  PathInterpolator(path)
} else {
  LinearInterpolator()
}

Java

Interpolator myInterpolator = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  Path path = new Path();
  path.moveTo(0.0f, 0.0f);
  path.cubicTo(0.5f, 0.7f, 0.1f, 1.0f, 1.0f, 1.0f);
  myInterpolator = new PathInterpolator(path);
} else {
  myInterpolator = new LinearInterpolator();
}

В результате получается такая же кривая, как и в примере с кубической кривой Безье, но с использованием Path.

Вы также можете определить интерполятор пути как ресурс XML:

<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
    android:controlX1="0.5"
    android:controlY1="0.7"
    android:controlX2="0.1f"
    android:controlY2="1.0f"/>

Созданный объект PathInterpolator можно передать методу Animator.setInterpolator(). Animator использует интерполятор, чтобы определить время или кривую пути при запуске.

Kotlin

val animation = ObjectAnimator.ofFloat(view, "translationX", 100f).apply {
    interpolator = myInterpolator
    start()
}

Java

ObjectAnimator animation = ObjectAnimator.ofFloat(view, "translationX", 100f);
animation.setInterpolator(myInterpolator);
animation.start();