Android

[Android] 안드로이드 - 액티비티 화면전환 애니메이션과 플래그 (액티비티만으로 탭바 레이아웃 만들기)

NukeOlaf 2020. 6. 30. 02:35

현재 Metaler 앱은 Fragment 가 아닌 Activity 만을 사용하여 만들어졌다.

그러나, Activity 만을 사용해서 탭바를 구현해야하는 점이 번거로웠다.

액티비티 스택을 어떻게 관리해야하며, 화면전환은 어떻게 해야 진짜 탭바 레이아웃처럼 보이게 할 수 있을까? 라는 고민에 대한 해결책이다.

1. 우선은 탭바 버튼을 누를때 액티비티의 화면전환 애니메이션을 제거하자.

실제 프래그먼트로 이루어진 탭바 레이아웃의 경우, 탭바 버튼을 누를때 화면이 움직이지 않는다. 즉, 애니메이션이 없다는 얘기이다. 그래서 나는 Animation Style 을 없앤 AppTheme 을 만든 다음, Manifest 파일에서 애니메이션이 제거되어야 하는 탭바 액티비티에 NoAnimTheme 을 설정해주었다. screenOrientation 의 경우, 일반적인 탭바 레이아웃으로 구성된 앱들은 가로화면(landscape)을 막아두었으므로, 세로(portrait)고정으로 설정해둔 것이다.

(1) res/values/styles

<style name="AnimTheme" parent="AppTheme">
    <item name="android:windowAnimationStyle">@style/CustomAnim</item>
</style>

(2) Manifest.xml

...
<activity
    android:name=".view.home.ActivityHome"
    android:screenOrientation="portrait"
    android:theme="@style/NoAnimTheme" />
<activity
    android:name=".view.mypage.ActivityMyPage"
    android:screenOrientation="portrait"
    android:theme="@style/NoAnimTheme" />
 ...

코드적으로 overridingPendingTransition(0,0) 을 사용하더라도 위와 같이 애니메이션 효과를 제거할 수 있지만, 위와 같이 style 을 지정하여 Manifest 파일에서 설정해주는 것이 좀 더 관리하기 편하다.

 

2. 인텐트 플래그를 BRING_TO_FRONT 로 설정한다

애니메이션이 제거되었다고 끝난것이 아니다. 탭 바 레이아웃에서는 다른 탭을 갔다가 돌아와도 이전의 탭의 상태가 저장되어있다. 이것을 구현하기 위해서 액티비티 스택에 이미 존재하는 액티비티를 호출하는 경우, 해당 액티비티를 가장 맨 앞으로 보내는 인텐트 플래그인 BRING_TO_FRONT 붙이도록 한다.

...
private fun startHomeActivity() {
    Intent(this, ActivityHome::class.java).apply {
        flags = Intent.FLAG_ACTIVITY_REORDER_TO_FRONT
    }.also {
        startActivity(it)
    }
}
 private fun startMyPageActivity() {
    Intent(this, ActivityMyPage::class.java).apply {
        flags = Intent.FLAG_ACTIVITY_REORDER_TO_FRONT
    }.also {
        startActivity(it)
    }
}
...

 

3. 백 버튼 (뒤로가기 버튼) 의 기능을 오버라이딩 한다.

이제 액티비티만으로 탭바 레이아웃처럼 보이게 만들었다. 하지만 한가지 아쉬운 점이 있다. 바로, 뒤로가기 버튼을 눌렀을때, 이전의 액티비티로 이동한다는 것이다. 일반적인 탭바 레이아웃에서는 뒤로가기 버튼을 눌러도 이전의 화면으로 이동하지 않고 앱이 종료된다. 해당 기능을 비슷하게 구현하기 위해 백버튼을 눌렀을시, finishAffinity() 를 통해 모든 스택을 비우고 앱을 종료하도록 구현했다.

private var firstTime: Long = 0
private var secondTime: Long = 0
override fun onBackPressed() {
    secondTime = System.currentTimeMillis()
    makeToast("뒤로버튼을 한번 더 누르시면 종료됩니다")
    if (secondTime - firstTime < 2000) {
        super.onBackPressed()
        finishAffinity()
    }
    firstTime = System.currentTimeMillis()
}

이 경우, 사용자가 백버튼을 실수로 한 번만 눌렀을때도 앱이 종료되므로, 처음 뒤로가기 버튼을 눌렀을 때 사용자에게 앱이 종료된다고 고지한뒤, 뒤로가기 버튼을 한 번 더 눌러야 앱이 종료되도록 구현한 것이다.

이렇게 앱을 구현하게 되면, Activity 만을 이용해서 탭 바 레이아웃을 흉내내어 구현할 수 있다.

 

4. (추가) 상세 페이지 액티비티를 열때는 왼쪽에서 오른쪽으로 열리는 애니메이션 설정하기

위와 같이 탭바 레이아웃을 구현했으나, 상세페이지 액티비티와 같은 탭바 관련 액티비티가 아닌 경우에 애니메이션 설정을 주고 싶을 수 있다. 나의 경우, Metaler 앱을 개발하면서 아래와 같이 게시물 목록 액티비티에서 게시물 상세 페이지로 이동할 때, 왼쪽에서 오른쪽으로 열리도록 설정하고 싶었다.

액티비티에 왼쪽에서 오른쪽으로 열리는 커스텀 애니메이션을 주는 방법은 아래와 같다.

(1) res 폴더 아래에 anim 폴더 생성

(2) hold.xml 추가
액티비티가 열릴때, 기존의 액티비티는 뒤에 가만히 있도록 하는 효과이다

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

 

(3) slide_in_right.xml 추가
액티비티가 오른쪽에서 왼쪽방향으로 슬라이드 되며 나타나는 애니메이션 효과이다.

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="@android:integer/config_shortAnimTime"
        android:fromXDelta="100%p"
        android:interpolator="@android:anim/decelerate_interpolator"
        android:toXDelta="0" />
</set>

(4) slide_out_right.xml 추가
엑티비티가 오른쪽으로 슬라이드 되면 사라지는 애니메이션 효과이다.

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

(5) res/values/styles 에 커스텀 애니메이션 style 추가

<style name="AnimTheme" parent="AppTheme">
    <item name="android:windowAnimationStyle">@style/CustomAnim</item>
</style>

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

(6) Manifest.xml

해당 커스텀 애니메이션을 사용할 Activity 태그에 애니메이션 style 을 설정해준다

...
<activity
    android:name=".view.detail.ActivityDetail"
    android:screenOrientation="portrait"
    android:theme="@style/AnimTheme" />
<activity
...

 

참고 사이트>>>

https://arabiannight.tistory.com/entry/286

https://developer.android.com/guide/components/activities/tasks-and-back-stack?hl=ko

https://itpangpang.xyz/268

https://www.warpdesign.fr/android-replace-default-transitions-with-slides-in-activities/

https://whereisusb.tistory.com/19

https://technote.kr/64

https://dwfox.tistory.com/26

https://medium.com/@logishudson0218/android-%EC%95%A0%EB%8B%88%EB%A9%94%EC%9D%B4%EC%85%98-%EC%9D%B4%EC%9A%A9%ED%95%9C-%ED%99%94%EB%A9%B4-%EC%8A%AC%EB%9D%BC%EC%9D%B4%EB%94%A9-7245c93c1c01

https://woochan-dev.tistory.com/37