Анимация в Android

Трудно представить себе мобильную разработку без анимированных элементов. Они весёлые, красивые и обладают силой убеждения, которой нет у статических элементов интерфейса.

Создание анимации, которая делает объекты на экране словно живыми может показаться таким же сложным, как аэрокосмическое проектирование. Не бойтесь, у Android довольно много инструментов, которые помогут вам создавать анимацию относительно легко. 🙂

В этом уроке вы научитесь комфортно работать с некоторыми необходимыми инструментами для анимации по мере того как вы будете запускать Доге на ракете в космос (возможно, даже на Луну) и, надеюсь, надёжно возвращать его на землю. 🙂

Создавая анимацию Доге, вы научитесь:

  • Создавать анимацию свойств (Property Animation) — самую полезную и простую анимацию в Android;
  • Перемещать и скрывать представления (views);
  • Объединять анимации в последовательность или запускать их одновременно;
  • Повторять и обращать анимации;
  • Регулировать время анимации;
  • Ракетостроению. 🙂

Необходимые требования: урок посвящён анимации в Android, поэтому вам нужны базовые знания в программировании на Android, а также быть знакомыми с Java, Android Studio и XML-разметками.

Начало работы

Анимация это очень интересная тема для изучения! Лучший способ стать мастером создания анимации это пачкание рук в коде. 🙂

Сначала загрузите стартовый проект. Импортируйте его в Android Studio, затем запустите на своём устройстве. Вы найдёте всё, что вам нужно, чтобы сделать это быстро.

На вашем устройстве отобразится список всех анимаций, которые вы реализуете в процессе.

Нажмите на любой элемент в списке.

Вы должны увидеть два статических изображения: Доге и ракету, причём Доге готов прокатиться. Пока все экраны одинаковы и ни один ещё не анимирован.

Как работает анимация свойств (Property Animation)?

Прежде чем вы начнёте работать с первой анимацией, немного пройдите по дороге теории, чтобы понять логику магии. 🙂

Представьте, что вам нужно анимировать запуск ракеты с нижнего края экрана до верхнего края и что ракета должна сделать это ровно через 50 мс.

Вот график, показывающий, как позиция ракеты меняется со временем:

Анимация выше кажется гладкой и непрерывной. Однако смартфоны являются цифровыми и работают с дискретными значениями. Время для них непрерывно не течёт, оно продвигается крохотными шагами.

Анимация состоит из множества статичных изображений, более известных как кадры, которые отображаются один за другим в течение определённого периода времени. Концепция сегодня такая же, как при создании первых мультфильмов, однако рендеринг немного отличается.

Истекшее время между кадрами называется задержкой обновления кадра (frame refresh delay) — по умолчанию для Property Animation она равна 10 мс.

Здесь анимация отличается от того, что было в первые годы существования кино: когда вы знаете, что ракета движется с постоянной скоростью, вы можете рассчитать положение ракеты в любой момент времени.

Ниже вы видите шесть кадров. Заметье, что:

  • В начале анимации ракета находится в нижней части экрана;
  • Положение ракеты изменяется на одну и ту же часть пути с каждым кадром;
  • К концу анимации ракета находится в верхней части экрана.

TL/DR: при рисовании определённого кадра вы вычисляете положение ракеты в зависимости от продолжительности и частоты обновления кадров.

К счастью, вам не нужно рассчитывать всё вручную, потому что ValueAnimator рад сделать это за вас.

Чтобы создать анимацию, вы просто указываете начальное и конечное значение объекта, который будет анимирован, а также продолжительность. Кроме того, вам нужно установить слушатель (listener) для вызова обновления позиции вашей ракеты для каждого кадра.

Интерполяторы времени

Вы, наверное, заметили, что ваша ракета движется с одинаковой постоянной скоростью во время анимации — не слишком реалистично. Material design поощряет вас создавать яркие анимации, которые привлекают внимание пользователя, когда они ведут себя более естественным образом.

В основе анимации Android лежат интерполяторы времени. ValueAnimator включает в себя эти интерполяторы — он имеет объект, который реализует интерфейс TimeInterpolator. Интерполяторы времени определяют, как анимация изменяется с течением времени.

Посмотрите ещё раз на график изменений позиции во времени в простейшем случае — Linear Interpolator.

Вот как LinearInterpolator реагирует на изменение времени.

В зависимости от времени, положение ракеты изменяется с постоянной скоростью или линейно.

Анимация также может иметь нелинейную интерполяцию. Одним из таких примеров является AccelerateInterpolator, который выглядит намного интереснее.

Он удваивает входное значение, заставляя ракету медленно стартовать и быстрее ускоряться — точно так же, как настоящая ракета!

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

Ваша первая анимация

Потратьте некоторое время, чтобы ознакомиться с проектом, прежде чем двигаться дальше. Пакет com.raywenderlich.rocketlaunch.animationactivities содержит BaseAnimationActivity и все другие активности, которые расширяют этот класс.

Откройте файл activity_base_animation.xml в папке res/layout.

В корневом каталоге вы найдёте FrameLayout, который содержит два экземпляра ImageView с изображениями. У одного есть rocket.png, а у другого есть doge.png. Оба имеют android:layout_gravity, установленный на bottom|center_horizontal, чтобы заставить изображения отображать в центре нижней части экрана.

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

Перейти в любой файл — command + O на Mac / Ctrl + N на Linux и Windows.

Перейти к классу Java — command + Shift + O на Mac / Ctrl + Shift + N на Linux и Windows.

BaseAnimationActivity это суперкласс для всех других анимационных активностей в этом приложении.

Откройте BaseAnimationActivity.java и загляните внутрь. В верхней части находятся переменные View, которые доступны из всех анимационных активностей:

  • mRocket — изображение ракеты;
  • mDoge — изображение Доге;
  • mFrameLayout — FrameLayout, который содержит в себе mRocket и mDoge;
  • mScreenHeight — переменная, равная высоте экрана.

Обратите внимание, что mRocket и mDoge оба являются ImageView, но объявлены как View, поскольку анимация свойств работает со всеми типами View.

Взгляните на onCreate(), чтобы просмотреть код:

// 1
super.onCreate(savedInstanceState);

// 2
setContentView(R.layout.activity_base_animation);
mRocket = findViewById(R.id.rocket);
mDoge = findViewById(R.id.doge);
mFrameLayout = findViewById(R.id.container);

// 3
mFrameLayout.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View v) {
    // 4
    onStartAnimation();
  }
});

Вот что вы здесь делаете:

  • вызываете метод onCreate() для суперкласса;
  • Применяет разметку XML и привязываете FrameLayout, mRocket и mDoge к их соответствующим представлениям;
  • Устанавливаете onClickListener в FrameLayout;
  • Вызываете onStartAnimation(), когда пользователь нажимает на экран. Это абстрактный метод, определяемый каждой активностью, которые наследуют BaseAnimationActivity.

Этот базовый код распределяется на всех активности, которые вы будете редактировать в этом уроке. Теперь, когда вы знакомы с ними, время начать настройку!

Запуск ракеты

Доге никуда не полетит пока не начнёте запуск ракеты, и это лучная анимация для начала поскольку она довольно простая. Кто бы мог подумать, что наука ракетостроения так проста!?

Откройте LaunchRocketValueAnimatorAnimationActivity.java и добавьте следующий код в тело onStartAnimation():

//1
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, -mScreenHeight);

//2
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  @Override
  public void onAnimationUpdate(ValueAnimator animation) {
    //3
    float value = (float) animation.getAnimatedValue();
    //4
    mRocket.setTranslationY(value);
  }
});

//5
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.setDuration(DEFAULT_ANIMATION_DURATION);
//6
valueAnimator.start();
  1. Создайте экземпляр ValueAnimator, вызвав статический метод ofFloat. Он принимает числа с плавающей запятой, которые будут применяться к указанному свойству анимированного объекта с течением времени. В этом случае значения начинаются с 0 и заканчиваются на -mScreenHeight. Начало координат в Android находится в верхнем левом углу, поэтому сдвиг по Y в ракете изменяется от 0 до отрицательного по высоте экрана — он перемещается снизу вверх.
  2. Вывозите addUpdateListener() и передайте слушателю. ValueAnimator вызывает слушатель с каждым обновлением до анимированного значения — помните о задержке по умолчанию в 10 мс.
  3. Получите текущее значение от аниматора и преобразуйте его в float. Текущий тип значения — float, потому что вы создали ValueAnimator с ofFloat.
  4. Измените положение ракеты, использую setTranslationY().
  5. Настройте продолжительность аниматора и интеполятор.
  6. Запустите анимацию.

Соберите и запустите проект. Выберите «Запустить ракету» в списке. Появится новый экран. Нажмите на него!

Это было весело, правда? 🙂 Не беспокойтесь о том, что Доге остался позади — он вскоре поймает свою ракету на Луну.

Добавление вращения на ракету

Как насчет того, чтобы дать ракете небольшое вращение? Откройте RotateRocketAnimationActivity.java и добавьте следующий код в onStartAnimation():

// 1
ValueAnimator animator = ValueAnimator.ofFloat(0, 360);

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  @Override
  public void onAnimationUpdate(ValueAnimator animation) {
    float value = (float) animation.getAnimatedValue();
    // 2
    mRocket.setRotation(value);
  }
});

animator.setInterpolator(new LinearInterpolator());
animator.setDuration(DEFAULT_ANIMATION_DURATION);
animator.start();

Можете заметить разницу?

  1. Изменилось значение аниматора, теперь он изменяется от 0 до 360, потому что ракета должна совершить полный оборот. Обратите внимание, что вы можете сзодать эффект разворота от 0 до 180.
  2. Вместо setTranslationY вы вызываете метод setRotation, потому что нужно задать вращение.

Соберите и запустите проект. Выберите «Вращать ракету». Нажмите на новый экран.

Ускорение запуска

Откройте AccelerateRocketAnimationActivity.java и добавьте следующий код к вашему старому другу onStartAnimation():

// 1
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, -mScreenHeight);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  @Override
  public void onAnimationUpdate(ValueAnimator animation) {
    float value = (float) animation.getAnimatedValue();
    mRocket.setTranslationY(value);
  }
});

// 2 - Here set your favorite interpolator
valueAnimator.setInterpolator(new AccelerateInterpolator(1.5f));
valueAnimator.setDuration(DEFAULT_ANIMATION_DURATION);

// 3
valueAnimator.start();

Вышеприведённый код идентичен onStartAimation() в LaunchRocketValueAnimationActivity.java за исключением одной строки: интерполятор, используемый для setInterpolator().

Соберите и запустите проект. Выберите «Ускорить ракету» в списке. Нажмите на новый экран, чтобы увидеть, как ведёт себя ваша ракета.

Опять же, мы видим, как бедный Доге не ловит ракету на Луну… бедный парень. Держись, приятель!

Поскольку вы использовали AccelerateInterpolator, вы должны увидеть ускорение ракеты после подъёма. Не стесняйтесь играть с интерполяторами, если хотите.

Какие свойства вы можете анимировать?

До сих пор у вас анимированы только позиция и поворот для View, но ValueAnimator не заботится о том, что вы делаете со значение, которое он поставляет.

Вы можете указать ValueAnimator для анимации значения с использованием любого из следующих типов:

  • float, если вы создаёте экземпляр ValueAnimator с функцией ofFloat;
  • int, если вы делаете это с помощью ofInt;
  • ofObject для случае, когда float или int недостаточно — он часто используется для анимации цветов.

Вы также можете анимировать любое свойство View. Вот некоторые примеры:

  • setScaleX(float) и setScaleY(float) — позволяют вам масштабировать объект по оси Х или Y независимо или вызывая их с одинаковыми параметрами для изменения размера;
  • setTranslationX(float) и setTranslation(Y) — позволяют вам изменить положение объекта на экране;
  • setAlpha(float) — прозначность анимированного объекта: 0 — полностью прозрачный, 1 — полностью непрозрачный;
  • setRotation(float) — поворачивает объект на экране. Аргумент задаётся в градусах, поэтому 360 означает полный поворот по часовой стрелке. Вы можете указать и отрицательные значения, например -90, что означает разворот против часовой стрелки;
  • setRotationX(float) и setRotationY(float) — то же самое, что и setRotation, но вдоль оси X и Y. Они позволяют поворачивать трехмерные объекты;
  • setBackgroundColor(int) — позволяет установить цвет. Целочисленный аргумент должен указывать цвет как константы Android (Color.YELLOW, Color.BLUE).

ObjectAnimator

Знакомьтесь с ObjectAnimator, подклассом ValueAnimator. Если вам нужно анимировать только одно свойства одного объекта, то ObjectAnimator может быть вашим лучшим другом.

В отличие от ValueAnimator, где вы должны установить слушатель и сделать что-то со значением, ObjectAnimator может обрабатывать всё это почти автоматически. 🙂

Перейдите в класс LaunchRocketObjectAnimatorAnimationActivity.java и добавьте следующий код:

// 1
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mRocket, "translationY",
  0, -mScreenHeight);
// 2
objectAnimator.setDuration(DEFAULT_ANIMATION_DURATION);
objectAnimator.start();

Вот что вы делаете:

  1. Создаёте экземпляр ObjectAnimator (как вы делали ValueAnimator), за исключением того, что первый имеет ещё два параметра:
    • mRocket — объект для анимации;
    • Объект должен иметь метод-сеттер вида set»Property name»(), и свойство, которое вы хотите изменить, например «translationY». Вы можете это сделать, поскольку mRocket является объектом класса View, у которого есть доступный setter setTranslationY().
  2. Устанавливаете продолжительность анимации и запускаете её.

Соберите и запустите проект. Выберите «Запустить ракету (ObjectAnimator)» в списке. Нажмите на экран

Ракета ведёт себя также, как и с ValueAnimator, но кода стало меньше. 🙂

Примечание: У ObjectAnimator есть ограничение — он не может анимировать два объекта одновременно. Чтобы обойти это, нужно создать два экземпляра ObjectAnimator.

Рассмотрите свои варианты использования и количество кода, когда вы решаете между ObjectAnimator и ValueAnimator.

Анимирование цвета

Говоря о случаях использования, существует анимирование цвета, которое нужно учитывать. Ни одна из функций ofFloat() и ofInt() не может построить ваш аниматор и получить хорошие результаты при работе с цветами. Вам лучше использовать ArgbEvalucator.

Откройте ColorAnimationActivity.java и поместите этот код в onStartAnimation():

//1
ObjectAnimator objectAnimator = ObjectAnimator.ofObject(mFrameLayout, "backgroundColor",
  new ArgbEvaluator(),
  ContextCompat.getColor(this, R.color.background_from),
  ContextCompat.getColor(this, R.color.background_to));

// 2
objectAnimator.setRepeatCount(1);
objectAnimator.setRepeatMode(ValueAnimator.REVERSE);

// 3
objectAnimator.setDuration(DEFAULT_ANIMATION_DURATION);
objectAnimator.start();

В приведённом выше коде вы:

  1. Вызываете метод ObjectAnimator.ofObject и даёте ему следующие аргументы:
    • mFrameLayout — объект со свойством, которое нужно анимировать;
    • «backgoundColor» — свойство, которое вы анимируете;
    • new ArgbEvalucator() — дополнительный аргумент, который указывает, как интерполировать между двумя разными значениями цвета ARGB (Alpha, Red, Green, Blue);
    • Начальное и конечное значения цвета — вы используете ComtextCompat.getColor(), чтобы получить идентификатор цветового ресурса.
  2. Устанавливаете количество повторений анимации с помощью setRepeatCount(). Затем вы используете setRepeatMode(), чтобы определить, что делает анимация, когда она достигает конца. Подробнее об этом скоро.
  3. Задаёте продолжительность и запускаете анимацию.

Соберите и запустите проект. Выберите «Цвет фона» в списке и нажмите на экран.

Это удивительно! Эй, вы быстро это понимаете. Такое гладкое изменение цвета фона. 🙂

Объединение анимаций

Анимация довольно удивительная вещь, но вы изменили только одно стройство и один объект за раз. Анимация не должна быть настолько ограничекна.

Пришло время отправить Доге на Луну. 🙂

AnimatorSet позволяет вам воспроизводить несколько анимаций вместе или последовательно. Вы передаёте свой первый аниматор в метод play(), который принимает объект Animator в качестве аргумента и возвращает построитель.

Затем вы можете вызвать следующие методы в этом построителе, все из которых имеют объект Animator в качестве аргумента:

  • with() — для воспроизведения аниматора, переданного как аргумент одновременно с первым, указанным в play();
  • before() — для воспроизведения до;
  • after() — для воспроизведения после.

Вы можете создавать целые цепочки вызовов.

Откройте LaunchAndSpinAnimatorSetAnimatorActivity.java в своём редакторе и поместите следующий код в onStartAnimation():

// 1
ValueAnimator positionAnimator = ValueAnimator.ofFloat(0, -mScreenHeight);

// 2
positionAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  @Override
  public void onAnimationUpdate(ValueAnimator animation) {
    float value = (float) animation.getAnimatedValue();
    mRocket.setTranslationY(value);
  }
});

// 3
ObjectAnimator rotationAnimator = ObjectAnimator.ofFloat(mRocket, "rotation", 0, 180f);
// 4
AnimatorSet animatorSet = new AnimatorSet();
// 5
animatorSet.play(positionAnimator).with(rotationAnimator);
// 6
animatorSet.setDuration(DEFAULT_ANIMATION_DURATION);
animatorSet.start();

Вот что вы делаете в этом блоке:

  1. Создаёте новый ValueAnimator.
  2. Прикрепляете AnimatorUpdateListener к ValueAnimator, который обновляет положение ракеты.
  3. Создаёте ObjectAnimator, второй аниматор, который обновляет вращение ракеты.
  4. Создаёте новый экземпляр AnimatorSet.
  5. Указываете, что вы хотите выполнить positionAnimator вместе с rotationAnimator.
  6. Устанавливаете проодлжительность и вызываете start().

Соберите и запустите проект. Выберите «Запустить и вращать (AnimatorSet)». Нажмите на экран.

Доге бросает вызов законам физики.

Существует отличный инструмент для упрощения анимации нескольких свойств одного и того же объекта. Инструмент называется…

ViewPropertyAnimator

Одна из самых больших особенностей кода, используемых ViewPropertyAnimator, заключается в просто написания и чтения кода — вот увидите.

Откройте LaunchAndSpinViewPropertyAnimatorAnimationActivity.java и добавьте следующий код в onStartAnimation():

  mRocket.animate().translationY(-mScreenHeight)
    .rotationBy(360f)
    .setDuration(DEFAULT_ANIMATION_DURATION)
    .start();

Здесь animate() возвращается экземпляр ViewPropertyAnimator, чтобы вы могли связать вызовы.

Соберите и запустите проект. Выберите «Запустить и вращать (ViewPropertyAnimation)» и вы увидите ту же анимацию. что и в предыдущем разделе.

Сравните код этого раздела с фрагментом кода AnimatorSet, который вы реализовали в предыдущем разделе:

ValueAnimator positionAnimator = ValueAnimator.ofFloat(0, -mScreenHeight);

positionAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  @Override
  public void onAnimationUpdate(ValueAnimator animation) {
    float value = (float) animation.getAnimatedValue();
    mRocket.setTranslationY(value);
  }
});

ObjectAnimator rotationAnimator = ObjectAnimator.ofFloat(mRocket, "rotation", 0, 360f);

AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(positionAnimator).with(rotationAnimator);
animatorSet.setDuration(DEFAULT_ANIMATION_DURATION);
animatorSet.start();

ViewPropertyAnimator может обеспечить лучшую производительность для нескольких одновременных анимаций. Он оптимизирует недействительные вызовы, поэтому они выполняются только один раз для нескольких свойств — в отличие от каждого анимированного свойства, вызывающего его собственную недействительность отдельно.

Анимирование одного и того же свойства двух объектов

Хорошей особенностью ValueAnimator является то, что вы можете повторно использовать его анимированное значение и примернять его к как можно большему количеству объектов.

Проверьте это, открыв FlyWithDogeAnimationActivity.java и добавив следующий код в onStartAnimation():

//1
ValueAnimator positionAnimator = ValueAnimator.ofFloat(0, -mScreenHeight);
positionAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  @Override
  public void onAnimationUpdate(ValueAnimator animation) {
    float value = (float) animation.getAnimatedValue();
    // You can use value to set properties of many objects
    mRocket.setTranslationY(value);
    mDoge.setTranslationY(value);
  }
});

//2
ValueAnimator rotationAnimator = ValueAnimator.ofFloat(0, 360);
rotationAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  @Override
  public void onAnimationUpdate(ValueAnimator animation) {
    float value = (float) animation.getAnimatedValue();
    mDoge.setRotation(value);
  }
});

//3
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(positionAnimator).with(rotationAnimator);
animatorSet.setDuration(DEFAULT_ANIMATION_DURATION);
animatorSet.start();

В приведённом выше коде вы просто создали три аниматора:

  1. positionAnimator — для изменения положения как mRocket, так и mDoge.
  2. rotationAnimator — для вращения Доге.
  3. animatorSet — для объединения двух аниматоров.

Обратите внимание, что вы устанавливаете перевод для двух объектов одновременно в первом аниматоре.

Соберите и запустите проект. Выберите «Не оставляйте Доге позади (Анимирование двух объектов)». Вы знаете, что делать. На Луну!

Слушатели анимации

Анимация обычно подразумевает, что определённое действие произошло или произойдёт. Как правильно, что бы ни происходило, обычно приходит в конце вашей фантастической анимации.

Вы не можете наблюдать, но знаете, что ракета останавливается и остаётся на экране, когда анимация заканчивается. Если не планируете высаживать его или закрывать активность, вы можете удалить View, чтобы сэкономить ресурсы.

AnimatorListener получает уведомление от аниматора при следующих событиях:

  • onAnimationStart() — при запуске анимации;
  • onAnimationEnd() — при завершении анимации;
  • onAnimationRepeat() — при повторении анимации;
  • onAnimationCancel() — при отмене анимации.

Откройте WithListenerAnimationActivity.java и добавьте следующий код в onStartAnimation():

//1
ValueAnimator animator = ValueAnimator.ofFloat(0, -mScreenHeight);

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  @Override
  public void onAnimationUpdate(ValueAnimator animation) {
    float value = (float) animation.getAnimatedValue();
    mRocket.setTranslationY(value);
    mDoge.setTranslationY(value);
  }
});

// 2
animator.addListener(new Animator.AnimatorListener() {
  @Override
  public void onAnimationStart(Animator animation) {
    // 3
    Toast.makeText(WithListenerAnimationActivity.this, "Doge took off", Toast.LENGTH_SHORT)
      .show();
  }

  @Override
  public void onAnimationEnd(Animator animation) {
    // 4
    Toast.makeText(WithListenerAnimationActivity.this, "Doge is on the moon", Toast.LENGTH_SHORT)
      .show();
    finish();
  }

  @Override
  public void onAnimationCancel(Animator animation) {

  }

  @Override
  public void onAnimationRepeat(Animator animation) {

  }
});

// 5
animator.setDuration(5000L);
animator.start();

Структура вышеприведённого кода, за исключением части слушателя, должна выглядеть так же, как в предыдущем разделе. Вот что вы здесь делаете:

  1. Создаёте и настраиваете аниматор. Вы используете ValueAnimator для изменения положения двух объектов одновременно — вы не сможете сделать тоже самое с одним ObjectAnimator.
  2. Добавляете AnimatorListener.
  3. Показываете всплывающее сообщение при запуске анимации.
  4. И ещё одно сообщение, когда она заканчивается.
  5. Начинаете анимацию как обычно.

Соберите и запустите проект. Выберите «События анимации». Нажмите на экран. Следите за сообщениями!

Примечание: вы также можете добавить слушателя в ViewProperyAnimator, добавив setListener в цепочку вызовов до вызова start():

mRocket.animate().setListener(new AnimatorListener() {
  // Your action
})

В качестве альтенатива вы можете устанавливать начальные и конечные действия, вызывая withStartAction(Runnable) и withEndAction(Runnable). Это эквивалент AnimatorListener с соответствующими действиями.

Опции анимации

Анимирование — это не простые трюки, которые просто останавливаются и уходят. Они могут работать циклически, в обратном направлении, в течение определённой продолжительности и т.д.

В Android вы можете использовать следующие методы для настройки анимации:

  • setRepeatCount — указывается количество повторений анимации после первого запуска;
  • setRepeatMode — определяет, что должна делать анимация. когда она достигает конца;
  • setDuration — указывает общую продолжительность анимации.

Откройте FlyThereAndBackAnimationActivity.java и добавьте следующий код в onStartAnimation():

// 1
ValueAnimator animator = ValueAnimator.ofFloat(0, -mScreenHeight);

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  @Override
  public void onAnimationUpdate(ValueAnimator animation) {
    float value = (float) animation.getAnimatedValue();
    mRocket.setTranslationY(value);
    mDoge.setTranslationY(value);
  }
});

// 2
animator.setRepeatMode(ValueAnimator.REVERSE);
// 3
animator.setRepeatCount(3);

// 4
animator.setDuration(500L);
animator.start();

Здесь вы:

  1. Создаёте аниматор как обычно.
  2. Можно установить для параметра repeatMode одно из следующих значений (RESTART — возобновляет анимацию с самого начала и REVERSE — обращает направление анимации с каждой итерацией). В данном случае вы устанавливает его на REVERSE. потому что вы хотите, чтобы ракета взлетела, а затем вернулась в туже позицию, где и началась. Как и SpaceX! 🙂
  3. …Кроме того, вы делаете это дважды.
  4. Устанавливаете продолжительность и запускаете анимацию как обычно.

Примечание: Итак, почему третий раздел указывает количество повторов 3 раза? Каждое движение вверх-вниз потребляет два повторения, поэтому вам нужно три, чтобы дважды довести Доге до земли: один для приземления в первый раз, а два — для запуска и посадки снова.  Сколько раз вы хотели бы увидеть Доге? Поиграйте с этим!

Соберите и запустите проект. Выберите «Лететь туда и обратно (Опции анимации)» в списке. Нажмите на экран.

Вы должны увидеть, как ваша ракета прыгает, как кузнечик! Получи, Илон Маск! 🙂

Объявление анимации в XML

У вас всё получилось в лучшей части этого урока. В этом заключительном разделе вы узнаете, как объявить анимацию один раз и использовать повсюду — да, это правда, вы сможете безнаказанного использовать свои анимации.

Определяя анимацию в XML, вы разрешаете повторное использование анимаций по всему коду.

Определение анимации в XML имеет некоторое сходство с составлением макетов разметки.

Если в src/main/res у вас нет папки animator, то нажмите на res правой кнопкой мыши и выберите New, затем Android resource directory.

В появившемся окне выберите тип ресурса animator.

Перейдите в папку res/animator и нажмите правой кнопкой мыши, выберите New, затем Android resource file.

Введите имя файла jump_and_blind. Сохраните предварительно выбранный корневой элемент в Source set.

В открывшемся редакторе вы увидите следующее:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">

</set>

Доступны следующие теги XML:

  • set — то же, что и AnimatorSet;
  • animator — то же, что и ValueAnimator;
  • objectAnimator — вы правильно поняли, это ObjectAnimator.

При использовании AnimatorSet в XML вы вставляете объекты ValueAnimator и ObjectAnimator внутри него, подобно тому, как вы вставляете объекты View внутри объекта ViewGroup (RelativeLayout, LinearLayout и т.д.) в файлах разметки.

Замените содержимое jump_and_blink.xml следующим кодом:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
  android:ordering="together">
    
  <objectAnimator
    android:propertyName="alpha"
    android:duration="1000"
    android:repeatCount="1"
    android:repeatMode="reverse"
    android:interpolator="@android:interpolator/linear"
    android:valueFrom="1.0"
    android:valueTo="0.0"
    android:valueType="floatType"/>

  <objectAnimator
    android:propertyName="translationY"
    android:duration="1000"
    android:repeatCount="1"
    android:repeatMode="reverse"
    android:interpolator="@android:interpolator/bounce"
    android:valueFrom="0"
    android:valueTo="-500"
    android:valueType="floatType"/>
</set>

Здесь вы объявляете корневой элемент, тэг set. Его атрибут упорядочения может быть либо «вместе», либо «последовательно». Он выставлен на «вместе» по умолчанию, но вы можете указать его для ясности. Тэг set имеет два дочерних XML-тэга, каждый из которых является объектным.

Взгляните на следующие атрибуты objectAnimator:

  • android:valueFrom и android:valueTo — указывают начальные и конечные значения, когда вы создали ObjectAnimator;
  • android:valueType — тип значения, либо floatType, либо intType;
  • android:propertyName — свойство, которое вы хотите анимировать;
  • android:duration — длительность анимации;
  • android:repeatCount — тоже, что и setRepeatCount;
  • android:repeatMode — то же, что и setRepeatMode;
  • android:interpolator — указывает интерполятор. Он обычно начинается с @android:interpolator/. Начните вводить это, и Android Studio покажет все доступные интерполяторы по параметрам автозаполнения;
  • Вы не можете указать свой целевой объект здесь, но вы можете сделать это позже в Java.

В последнем блоке вы добавили два экземпляра objectAnimator в AnimatorSet, и они будут воспроизводиться вместе. Теперь, пришло время их использовать.

Перейдите в XmlAnimationActivity.java и добавьте следующий код в onStartAnimation():

  // 1
  AnimatorSet rocketAnimatorSet =
    (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.jump_and_blink);
  // 2
  rocketAnimatorSet.setTarget(mRocket);
  
  // 3
  AnimatorSet dogeAnimatorSet =
    (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.jump_and_blink);
  // 4
  dogeAnimatorSet.setTarget(mDoge);
  
  // 5
  AnimatorSet bothAnimatorSet = new AnimatorSet();
  bothAnimatorSet.playTogether(rocketAnimatorSet, dogeAnimatorSet);
  // 6
  bothAnimatorSet.setDuration(DEFAULT_ANIMATION_DURATION);
  bothAnimatorSet.start();

В приведённом выше коде вы делаете всего несколько вещей:

  1. Во-первых, вы загружаете AnimatorSet из файла R.animator.jump_and_blink, так же, как вы обычно загружаете разметку.
  2. Затем вы устанавливаете mRocket в качестве цели для только что загруженного аниматора.
  3. Ещё раз загружаете аниматор из того же файла
  4. Повторяете действия для mDoge.
  5. Теперь вы создаёте третий AnimatorSet и настраиваете его для одновременного воспроизведения первых двух.
  6. Устанавливаете продолжительность для корневого аниматора и запускаете.
  7. Уф! Осталось немного. 🙂

Соберите проект и запустите. Выберите «Прыгнуть и моргнуть (Анимация в XML) в списке. Нажмите на экран, чтобы увидеть результат своей работы.

Вы должны увидеть, как Доге прыгает, исчезает, а затем возвращается безопасно на землю. 🙂

Что делать дальше

Во время этого урока вы:

  • Создали и использовали анимацию свойств с помощью ValueAnimator и ObjectAnimator;
  • Настроили интерполятор времени для вашей анимации;
  • Анимировали положение, поворот и цвет;
  • Объединили анимации вместе;
  • Использовали впечатляющий ViewPropertyAnimator с помощью animate();
  • Повторили анимацию;
  • Определили анимацию в XML для повторного использования в проекте.

В принципе, вы только что получили супер-способности анимирования в Android.

Если вы хотите узнать больше, ознакомьтесь с доступными временными интерполяторами в документации Android (смотрите Known Indirect Subclasses). Если вас не устраивает ни один из них, вы можете создать свой собственный. Вы также можете устанавливать для своей анимации ключевые кадры (Keyframes), чтобы сделать её сложнее.

У Android есть и другие виды анимации, такие как View animation и Drawable animation. Вы также можете использовать API Canvas и OpenGL для создания анимации. Будьте на связи. 🙂

Share on VKShare on Facebook0Share on Google+0Tweet about this on TwitterShare on LinkedIn0Share on Tumblr0Email this to someoneShare on Reddit0
Нашли ошибку в тексте?

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *