Экран загрузки с использованием Physics Animation

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

Вчера я наткнулся на этот загрузочный экран приложения ShowBox, который является хорошим потоковым сервисом для фильмов и телешоу.

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

  1. Вращение, которое движется около координаты (0, 0) экрана.
  2. Переворот этого экрана книзу.

В этой статье я расскажу, как я достиг этой анимации и сделал следующую демонстрацию.

Спасибо Google за внедрение анимации на основе физики, представленной на Google I/O 2017, которая помогла мне выполнить первую часть с вращением.

Что такое анимация, основанная на физике?

До сих пор разработчики имели API для анимации, такие как Value Animators, Object Animators, где мы применяем различные интерполяторы, которые контролируют скорость изменения анимации. У всех них есть одна проблема: каждый раз приходится писать сложный код, когда приходится иметь дело со сложной анимацией, которая должна имитировать объекты реального мира. И наша реакция становится похожей на такую:

Добавив анимации на основе физики, Google сделала анимации более реалистичными для своих пользователей. Эти анимации включены в библиотеки поддержку, так что они обратно совместимы до API 16. Эти типы анимации приводятся в действие с помощью силы, которая контролирует ход анимации. Вы определяете характеристики этих сил, и затем они полностью берут на себя работу с анимацией.

Чтобы начать работу с этой анимацией, добавьте следующую библиотеку поддержки в блок dependencies файла build.gradle модуля приложения.

dependencies {
  ...
  implementation "com.android.support:support-dynamic-animation:27.0.2"
}

Вам не нужно будет определять продолжительность анимации или другие параметры. Сила, которую вы зададите, позаботится об анимациях сама.

API для анимации на основе физики предоставляет два типа анимации:

  1. Анимация пружины (Spring Animation). Эта анимация управляется силой упругости, где скорость вашей анимации будут зависеть от неё. Вы определяете все свойства силы, включая коэффициент демпфирования и жесткость. API предоставляет разные типы констант, чтобы легко их установить.
  2. Анимация броска (Fling Animation). Анимация, управляемая силой трения. Анимация броска имеет начальный импульс и постепенно замедляется. Она подчиняется законам трения, в которых сила трения пропорциональна скорости объекта, вследствие чего объект постепенно замедляется.

В этой статье я расскажу о Spring Animation, из которой я получил загрузочный экран. Достаточно говорить, перейдём к коду.

1. Создание силы упругости и её применение к SpringAnimation

SpringForce springForce = new SpringForce(0f);
relativeLayout.setPivotX(0f);
relativeLayout.setPivotY(0f);
SpringAnimation springAnimation =
    new SpringAnimation(relativeLayout, DynamicAnimation.ROTATION);
springForce.setDampingRatio(SpringForce.DAMPING_RATIO_HIGH_BOUNCY);
springForce.setStiffness(SpringForce.STIFFNESS_VERY_LOW);
springAnimation.setSpring(springForce);
springAnimation.setStartValue(80f);
  • В этой части кода мы инициализируем экземпляр SpringForce, передавая конструктору его положение равновесия в float.
  • Мы определяем точку опоры для RelativeLayout. Это будет (0, 0), потому что мы хотим, чтобы вращение происходило у начала экрана.
  • Начинаем определять экземпляр класса SpringAnimation, который будет принимать следующие параметры:
  1. Представление, которое мы хотим анимировать.
  2. DynamicAnimation, который сообщает, какое свойство представления мы хотим анимировать. В данном случае это будет вращение.

Теперь определяем свойства силы упругости. Я использовал коэффициент демпфирования DAMPING_RATIO_HIGH_BOUNCY и жесткость STIFFNESS_VERY_LOW. DAMPING_RATIO_HIGH_BOUNCY обеспечит более высокие колебания, а жесткость, равная STIFFNESS_VERY_LOW, сделает так, что объект будет медленно возвращаться в исходное состояние.

  • Теперь, наконец, мы передадим наш объект SpringForce в SpringAnimation и установим начальное значение для анимации.

2. Настройка DynamicAnimation.OnAnimationEndListener

Мы описали, что наша разметка должна вращаться около (0, 0) с заданным коэффициентом жесткости и демпфирования, и теперь нам нужно переместить разметку вниз после окончания анимации. Для этого API предоставляет нам следующие два слушателя:

  • OnAnimationUpdateListener — этот слушатель переопределяет метод onAnimationUpdate, который используется для получения изменений в процессе анимации.
  • OnAnimationEndListener — этот слушатель переопределяет метод onAnimationEnd, который используется для уведомления о завершении анимации, на которую он зарегистрирован.

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

springAnimation.addEndListener(new DynamicAnimation.OnAnimationEndListener() {
  @Override
  public void onAnimationEnd(DynamicAnimation animation, boolean canceled, float value,
      float velocity) {
    // код перемещения будет здесь
});

3. Перемещение разметки после получения уведомления о завершении и открытие второй активности

Теперь в onAnimationEnd мы будем использовать ViewPropertyAnimator, который является ещё одним классом в Android, доступным для анимирования свойств представлений, с помощью всего нескольких строк кода.

@Override
public void onAnimationEnd(DynamicAnimation animation, boolean canceled, float value,
    float velocity) {
  DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
  getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
  float height = (float) displayMetrics.heightPixels;
  float width = (float) displayMetrics.widthPixels;
  relativeLayout.animate()
      .setStartDelay(1)
      .translationXBy(width / 2)
      .translationYBy(height)
      .setListener(new Animator.AnimatorListener() {
        @Override public void onAnimationStart(Animator animator) {
        }

        @Override public void onAnimationEnd(Animator animator) {
          Intent intent = new Intent(getApplicationContext(), MainActivity.class);
          finish();
          getApplicationContext().startActivity(intent);
          overridePendingTransition(0, 0);
        }

        @Override public void onAnimationCancel(Animator animator) {
        }

        @Override public void onAnimationRepeat(Animator animator) {
        }
      })
      .setInterpolator(new DecelerateInterpolator(1f))
      .start();
}

Рассмотрим шаг за шагом:

  • Сначала мы получаем объект DisplayMetrics, чтобы узнать ширину и высоту экрана устройства.
  • У RelativeLayout мы вызываем метод animate(), который возвращает ссылку на объект ViewPropertyAnimator, после чего мы можем настроить и запустить анимацию.
  • После мы вызываем метод setStartDelay(), который устанавливает задержку перед запуском анимации, затем мы устанавливаем перемещение как по оси Х, так и по оси Y, в соответствии с шириной и высотой, которые мы получили выше.
  • После настройки анимации мы также добавляем слушателя к этому ViewPropertyAnimator, в котором, когда мы получим коллбек onAnimationEnd, мы запускаем вторую активность.

Примечание: не забудьте добавить overridePendingTransition(0, 0) после вызова startActivity(), который сообщит WindowManager отключить переход по умолчанию для второй активности.

  • Наконец, на этот ViewPropertyAnimator мы устанавливаем Interpolator и запускаем с помощью метода start().

4. В конце для объекта SpringAnimation вызываем метод start()

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

Нашли ошибку в тексте?

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

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