선생님, 개발을 잘하고 싶어요.

[잡학] Activity 전환 애니메이션 설정하기, overridePendingTransition 본문

개발/android 개발

[잡학] Activity 전환 애니메이션 설정하기, overridePendingTransition

알고싶은 승민 2020. 4. 19. 17:20

문제 상황

애플리케이션에서 화면 전환은 엄청 중요하죠. 이렇게 중요한 화면 전환, 좀 더 이쁘고 의도에 맞게 하는 방법 없을까요?🤔 애니메이션과 BaseActivity 구현체를 사용해서 간단하게 구현해 봅시다.

 

그냥 뙇 뜨는게 보기 싫다면?

overridePendingTransition

 간단히 이 함수 하나만 있으면 화면 전환간 애니메이션을 실행할 수 있습니다.

overridePendingTransition(R.anim.none, R.anim.horizon_exit)

이 함수는 두개의 애니메이션 리소스를 함수 인자를 받는데요.

첫 번째 인자는, 새로 나타나는 화면이 취해야 하는 애니메이션

두 번째 인자는, 지금 화면이 취하는 애니메이션입니다.

 

위의 함수 콜은, 새로 나타는 화면은 가만히, 지금 화면은 오른쪽에서 왼쪽으로 슬라이딩하면서 퇴장하게 하는 코드입니다.

 

오른쪽에서 왼쪽으로 슬라이드 아웃

애니메이션 xml

자, 화면에 적용할 애니메이션을 추가해봅시다.

<!-- horizon_enter.xml -->
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="@integer/screen_in_time"
        android:fromXDelta="-100%"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:toXDelta="0%" />
</set>

 

왼쪽에서 오른쪽으로 슬라이드 하면서 들어오는 애니메이션 코드입니다.

 

이런 식의 구조입니다.

android:fromXDelta="-100%" -> 디바이스 스크린 왼쪽 부터
android:fromYDelta="0%" -> 디바이스 스크린에 꽉 차는 형태로

이동한다는 의미입니다. 

 

같은 원리로 위아래, 좌 우로 슬라이딩하는 애니메이션 코드를 만들어낼 수 있겠죠?

<!-- horizon_exit.xml -->
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="@integer/screen_out_time"
        android:fromXDelta="0%"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:toXDelta="-100%" />
</set>
<!-- vertical_enter.xml -->
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="@integer/screen_in_time"
        android:fromYDelta="100%"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:toYDelta="0%" />
</set>
<!-- vertical_exit.xml -->
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="@integer/screen_out_time"
        android:fromYDelta="0%"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:toYDelta="100%" />
</set>

 

아 그리고, 아무것도 안 하는 애니메이션 지정을 위한 애니메이션도 추가해 줍니다. 

공식 문서 상에서 overridePendingTransition의 인자로 0을 주면 아무런 애니메이션을 안 한다고 되어 있지만, 실제로는 검은 화면이 됩니다. 이상하죠?

 

<!-- none.xml -->
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="@integer/screen_in_time"
        android:fromXDelta="0%"
        android:fromYDelta="0%"
        android:toXDelta="0%"
        android:toYDelta="0%" />
</set>

 

overridePendingTransition 호출 위치

애니메이션 준비는 끝났으니, 함수를 호출합시다.

함수 호출은

 

Activity의 onCreate에서, 이 화면이 켜질 때 동작할 애니메이션을,

finish, onBackPressed에서, 화면이 꺼질 때 동작할 애니메이션을 지정해주면 됩니다.

볼까요?

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // 이 화면은, 왼쪽에서 오른쪽으로 슬라이딩 하면서 켜집니다.
    overridePendingTransition(R.anim.horizon_enter, R.anim.none)
}
fun someFunction() {
    finish()
    
    // 이 화면은, 오른쪽에서 왼쪽으로 슬라이딩 하면서 사라집니다.
    overridePendingTransition(R.anim.none, R.anim.horizon_exit)
}
override fun onBackPressed() {
    super.onBackPressed()
    if (isFinishing) {
        // back 버튼으로 화면 종료가 야기되면 동작한다.
        overridePendingTransition(R.anim.none, R.anim.horizon_exit)
    }
}

반드시 finish 이후에 불러야 한다는 점을 명심해주세요!

 

애플리케이션에 일괄 적용하기

모든 화면을 종료할 때, 이런 작업을 하는 건 귀찮은 일입니다. 앱 전체적으로 쉽게 화면 전환을 지정할 수 없을까요? 🤔

저는 상속을 사용해서 문제를 해결해 보았습니다.

 

모든 화면이 상속받는 BaseActivity 만들기

기존 Activity를 보시면, AppCompatActivity클래스를 상속받은 것을 확인할 수 있습니다. 

제일 처음 하실 일은, 우리만의 부모 BaseActivity 클래스를 만드는 것입니다.

abstract class BaseActivity(
    private val transitionMode: TransitionMode = TransitionMode.NONE
) : AppCompatActivity() {

    enum class TransitionMode {
        NONE,
        HORIZON,
        VERTICAL
    }
}

해당 화면이 어떤 형태로 켜지는 화면인지 정의하는 enum class를 정의했습니다.

 

NONE을 지정하면 시스템 기본으로

HORIZON을 지정하면 화면이 좌우로 슬라이딩되며 in / out 되게

VERTICAL로 지정하면 화면이 위아래로 슬라이딩되며 in / out  하는 것을 의도했습니다.

finish, onBackPressed 오버라이드 하기

 

그리고 부모 클래스의 함수를 오버라이드 해서 overridePendingTransition 호출을 BaseActivity에게 위임합시다.🤗

abstract class BaseActivity(
    private val transitionMode: TransitionMode = TransitionMode.NONE
) : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        onInject(savedInstanceState)
        super.onCreate(savedInstanceState)

        when (transitionMode) {
            TransitionMode.HORIZON -> overridePendingTransition(R.anim.horizon_enter, R.anim.none)
            TransitionMode.VERTICAL -> overridePendingTransition(R.anim.vertical_enter, R.anim.none)
            else -> Unit
        }
    }

    override fun finish() {
        super.finish()

        when (transitionMode) {
            TransitionMode.HORIZON -> overridePendingTransition(R.anim.none, R.anim.horizon_exit)
            TransitionMode.VERTICAL -> overridePendingTransition(R.anim.none, R.anim.vertical_exit)
            else -> Unit
        }
    }

    override fun onBackPressed() {
        super.onBackPressed()
        if (isFinishing) {
            when (transitionMode) {
                TransitionMode.HORIZON -> overridePendingTransition(R.anim.none, R.anim.horizon_exit)
                TransitionMode.VERTICAL -> overridePendingTransition(R.anim.none, R.anim.vertical_exit)
                else -> Unit
            }
        }
    }

    enum class TransitionMode {
        NONE,
        HORIZON,
        VERTICAL
    }
}

 

그리고 실제 화면에서 사용해 볼까요? 

// 이미 부모 클래스에게 화면 전환 애니메이션을 위임했습니다.
class ReviewActivity : BaseActivity(TransitionMode.VERTICAL) {
    // 아무것도 안하고, 평소 하시던 대로 개발하시면 됩니다.
}

위에서 아래로, 아래서 위로

쉽죠?

완료!

다 하셨습니다!

이제 화면 전환 애니메이션에 신경 쓸 필요 없이 애플리케이션 개발이 가능해졌습니다.

디자이너 요구사항이 변경돼서 화면 전환이 변경되어야 한다고요? BaseActivity를 사용해서 앱 전체에 통일된 방법으로 화면 전환 애니메이션을 제공하기 때문에 변화에도 적응하기 쉽습니다. 🤩

Comments