Как разработчик, я всегда стараюсь понять логику работы некоторых особенностей приложений Android и перепроектировать их в соответствии со своей логикой.
Вчера я наткнулся на этот загрузочный экран приложения ShowBox, который является хорошим потоковым сервисом для фильмов и телешоу.
Увидев это, я решил перестроить этот экран в соответствии с моей логикой. Я разбил эту анимацию на следующие части:
- Вращение, которое движется около координаты (0, 0) экрана.
- Переворот этого экрана книзу.
В этой статье я расскажу, как я достиг этой анимации и сделал следующую демонстрацию.
Спасибо 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 для анимации на основе физики предоставляет два типа анимации:
- Анимация пружины (Spring Animation). Эта анимация управляется силой упругости, где скорость вашей анимации будут зависеть от неё. Вы определяете все свойства силы, включая коэффициент демпфирования и жесткость. API предоставляет разные типы констант, чтобы легко их установить.
- Анимация броска (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, который будет принимать следующие параметры:
- Представление, которое мы хотим анимировать.
- 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()
Ваш загрузочный экран готов, теперь, скомпилировав и запустим проект, можно будет увидеть результат, показанный выше.