Домой Android разработкаUI и UX. Графика в Android Анимированные переходы в Android

Анимированные переходы в Android

by dilix
Beautiful screen transition

При программировании под андроид можно использовать уже ряд готовых анимаций переходов между экранами. Но что если дизайнер придумал более изощренные переходы? Рассмотрим какие есть возможности реализовать нестандартные смены экранов.

Активити и фрагменты

От того, используются ли переходы между Activity или все происходит в рамках разных фрагментов зависит и то, какие инструменты предлагает система для переходов между экранами.

Приложение с несколькими Activity

Когда используете несколько Activity, то можно использовать простые анимации переходов или создать красивые эффекты с shared element.

Простой переход между Activity

Simple activity transition

Можно использовать либо готовые переходы, которые предоставляет Android, либо определить свой, например

<?xml version="1.0" encoding="utf-8"?>
<translate
   xmlns:android="http://schemas.android.com/apk/res/android" 
   android:duration="@android:integer/config_longAnimTime" 
   android:fromXDelta="100%p" 
   android:toXDelta="0%p"/>

Можно либо переопределить переходы для всех Acitivty в теме приложения

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorPrimary</item>
    <item name="android:windowAnimationStyle">@style/CustomActivityAnimation</item>

...

<style name="CustomActivityAnimation" parent="@android:style/Animation.Activity">
    <item name="android:activityOpenEnterAnimation">@anim/slide_in_right</item>
    <item name="android:activityOpenExitAnimation">@anim/slide_out_left</item>
    <item name="android:activityCloseEnterAnimation">@anim/slide_in_left</item>
    <item name="android:activityCloseExitAnimation">@anim/slide_out_right</item>
...

Либо же переопределить переход в рамках отдельной Acitivty, вызвав

overridePendingTransition(R.anim.slide_in, R.anim.slide_out);

в onCreate вызываемой Activity.

Shared Element Transition
Shared element animation

Суть shared element transition в том, что общий элемент перетекает между двумя экранами, создавая видимость целостности двух Activity между собой.

Берете View с одного экрана. Говорите системе, что view с тем же id есть на следующем. Запускаете переход.

// get the element that receives the click event
val imgContainerView = findViewById<View>(R.id.img_container)

// get the common element for the transition in this activity
val androidRobotView = findViewById<View>(R.id.image_small)

// define a click listener
imgContainerView.setOnClickListener( {
    val intent = Intent(this, Activity2::class.java)
    // create the transition animation - the images in the layouts
    // of both activities are defined with android:transitionName="robot"
    val options = ActivityOptions
            .makeSceneTransitionAnimation(this, androidRobotView, "robot")
    // start the new activity
    startActivity(intent, options.toBundle())
})

Остальное Android OS все сделает за вас.

Single activity application

Суть single activity application в его названии. Ваше приложение будет состоять из одной активности, а экраны внутри будут реализованы как фрагменты. Такой подход придает гибкость и контролируемость переходам. В рамках View можно делать абсолютно что угодно.


Beautiful screen transition

https://github.com/danielzeller/Depth-LIB-Android-

Вы можете управлять любой View, применять любые transition и т.д. С Activity такое не прокатит, потому что слушать или влиять на скорость отработки закрытия и открытия активности на прямую не получится.

Архитектура переходов между фрагментами одной activity

Сделать базовую логику переходов между экранами просто. Определяем интерфейс

interface AnimatedTransitionFragment {
    fun exit() : Single<Boolean>
}

Не обязательно использовать Single из RxJava, можно установить любой тип callback. Метод exit() должен вернуть нечто, что можно «слушать» на предмет исполнения. Fragment, который должен поддерживать «выход» будет реализовывать интерфейс, приведенный выше.

Далее необходимо при переходе между фрагментами вызвать exit(). Подождать, когда Fragment исполнит необходимую анимацию, а затем перейти на новый Fragment, который может запустить анимацию «старта».

Если вы используете, например Cicerone, то можно переопределить свой AnimatedSupportAppNavigator

override fun applyCommands(commands: Array<out Command>?) {
        val topFragment = _fragmentManager?.fragments?.lastOrNull()
        val command = commands?.let { if (it.isNotEmpty()) it[it.size - 1] else null }
        (topFragment as? AnimatedTransitionFragment)?.let {
            if (shouldAnimatedTransition) {
                it.exit().subscribe { _: Boolean? ->
                    super.applyCommands(commands)
                }
            } else {
                super.applyCommands(commands)
            }
        } ?: let {
            super.applyCommands(commands)
        }
    }

Происходит все тоже самое, что в Cicerone, только теперь, если Fragment поддерживает анимацию выхода, сначала проиграется она.

Анимация открытия и закрытия Fragment

Анимация выхода из Fragment

Сам Fragment реализуя exit() проигрывает анимацию выхода и отдает управление дальше.

    override fun exit(): Single<Boolean> {
        exitAnimResult = SingleSubject.create()

        val views = getViewsToAnimate().filterNotNull() //Crashlytics will disagree with you...

        AdditiveAnimator()
            .setDuration(ANIMATION_DURATION)
            .targets(views).rotationY(ROTATION_FACTOR).scaleX(SCALE_FACTOR).scaleY(SCALEY_FACTOR)
            .setInterpolator(AccelerateInterpolator(2f))
            .addListener(object : SimpleAnimatorListener() {
                override fun onAnimationEnd(animation: Animator?) {
                    exitAnimResult?.onSuccess(true)
                    exitAnimResult = null
                }
            })
            .start()
        return exitAnimResult!!
    }

Для простоты используется AdditiveAnimation. Он позволяет легко управлять анимацией разных элементов и слушать окончание проигрывания.

Анимация входа во Fragment

При необходимости в onViewCreated можно запустить анимацию «входа».

    private fun entryScreenAnimation() {
        var shift = 500f
        for (view in listOf<View>(tvTitle, etFirstName, etLastName, btnNext)) {
            view.alpha = 0f
            view.translationY = shift
            shift += 100f
        }
        AdditiveAnimator()
            .setDuration(600)
            .targets(tvTitle, etFirstName, etLastName, btnNext).translationY(0f)
            .alpha(1f)
            .start()
    }

Это лишь база, необходимая для того, чтобы понимать как можно осуществлять навигацию между Activity и Fragment. Более сложные примеры зависят уже от конкретной задачи и прихоти дизайнера. Имея доступ к анимации на уровне View можно сделать любую мыслимую и не очень анимацию. Например можно запустить полноэкранную Lottie анимацию, сделанную в Adobe after effects.

Lottie animation

О Lottie можно почитать в мой статье инструменты Android разработчика.

Хочешь обсудить Android разработку?
Заходи к нам Вконтакте, на Facebook и в Телеграм!

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

Может быть интересно

Этот сайт использует Cookie файлы для улучшения вашего пользовательского взаимодействия. Используя данный сайт вы соглашается с этим. Принять Читать

Политика конфиденциальности и Cookies