뷰에서 뒤로 탐색 예측 애니메이션 지원 추가

뷰 또는 Compose를 사용하여 맞춤 인앱 속성 애니메이션과 전환, 맞춤 교차 활동 애니메이션, 뒤로 탐색 예측 동작이 있는 맞춤 교차 프래그먼트 애니메이션을 만들 수 있습니다. Compose 방식으로 시도하려면 뒤로 탐색 예측 애니메이션 지원 추가를 참고하세요.

Progress API를 사용하여 맞춤 전환 추가

AndroidX Activity 1.8.0-alpha01 이상에서는 뒤로 탐색 예측 진행 API를 사용하여 앱의 뒤로 탐색 예측 동작을 위한 맞춤 애니메이션을 개발할 수 있습니다. 진행 API는 뷰에 애니메이션을 적용하는 데 유용하지만 프래그먼트 간 전환에 애니메이션을 적용할 때는 제한사항이 있습니다. OnBackPressedCallback 내에 사용자가 뒤로 스와이프하는 동안 객체에 애니메이션을 적용하는 handleOnBackProgressed, handleOnBackCancelled, handleOnBackStarted 메서드를 도입했습니다. 시스템에서 제공하는 기본 애니메이션 또는 Material 구성요소 애니메이션보다 맞춤설정이 더 필요한 경우 이 메서드를 사용하세요.

대부분의 앱이 하위 호환 AndroidX API를 사용할 것으로 예상되지만 Android 14 이상에서 테스트할 수 있는 OnBackAnimationCallback 인터페이스 내에도 유사한 플랫폼 API가 있습니다.

AndroidX 전환과 함께 Progress API 사용

Progress API는 Android 14 이상에서 AndroidX 전환 1.5.0-alpha01 이상과 함께 사용하여 뒤로 탐색 예측 전환을 만들 수 있습니다.

  1. beginDelayedTransition 대신 TransitionManager#controlDelayedTransition을 사용하여 사용자가 뒤로 스와이프할 때 전환을 재생합니다.
  2. handleOnBackStarted 내에 전환을 만듭니다.
  3. 사용자가 뒤로 스와이프한 범위를 노출하는 BackEvent.progresscurrentFraction을 연결하여 handleOnBackProgressed 내에서 뒤로 이벤트로 전환을 재생합니다.
  4. 사용자가 handleOnBackPressed에서 뒤로 동작을 커밋한 후 전환을 완료합니다.
  5. 마지막으로 handleOnBackCancelled 내에서 전환 상태를 재설정합니다.

다음 동영상과 Kotlin 코드, XML은 OnBackPressedCallback으로 구현된 두 상자 간의 맞춤 전환을 보여줍니다.

    class MyFragment : Fragment() {

    val transitionSet = TransitionSet().apply {
        addTransition(Fade(Fade.MODE_OUT))
        addTransition(ChangeBounds())
        addTransition(Fade(Fade.MODE_IN))
    }
    ...
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        val callback = object : OnBackPressedCallback(enabled = false) {

            var controller: TransitionSeekController? = null

            @RequiresApi(34)
            override fun handleOnBackStarted(backEvent: BackEvent) {
                // Create the transition
                controller = TransitionManager.controlDelayedTransition(
                    binding.card,
                    transitionSet
                )
                changeTextVisibility(ShowText.SHORT)
            }

            @RequiresApi(34)
            override fun handleOnBackProgressed(backEvent: BackEvent) {
                // Play the transition as the user swipes back
                if (controller?.isReady == true) {
                    controller?.currentFraction = backEvent.progress
                }
            }

            override fun handleOnBackPressed() {
                // Finish playing the transition when the user commits back
                controller?.animateToEnd()
                this.isEnabled = false
            }

            @RequiresApi(34)
            override fun handleOnBackCancelled() {
                // If the user cancels the back gesture, reset the state
                transition(ShowText.LONG)
            }
        }

        binding.shortText.setOnClickListener {
            transition(ShowText.LONG)
            callback.isEnabled = true
        }

        this.requireActivity().onBackPressedDispatcher.addCallback(callback)
    }

    private fun transition(showText: ShowText) {
        TransitionManager.beginDelayedTransition(
            binding.card,
            transitionSet
        )
        changeTextVisibility(showText)
    }

    enum class ShowText { SHORT, LONG }
    private fun changeTextVisibility(showText: ShowText) {
        when (showText) {
            ShowText.SHORT -> {
                binding.shortText.isVisible = true
                binding.longText.isVisible = false
            }
            ShowText.LONG -> {
                binding.shortText.isVisible = false
                binding.longText.isVisible = true
            }
        }
    }
}
  
<?xml version="1.0" encoding="utf-8"?>
...
    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/card"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        ...>

        <TextView
            android:id="@+id/short_text"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            ... />

        <TextView
            android:id="@+id/long_text"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="gone"
            .../>

    </androidx.constraintlayout.widget.ConstraintLayout>

뒤로 탐색 예측 전환을 사용할 때는 다음 사항에 유의하세요.

  • isSeekingSupported를 사용하여 전환이 뒤로 탐색 예측을 지원하는지 확인합니다.
  • 맞춤 전환을 위해 true를 반환하도록 isSeekingSupported를 재정의합니다.
  • 애니메이션당 하나의 컨트롤러를 만듭니다.
  • 뒤로 탐색 예측 전환은 AndroidX 전환에서는 지원되지만 프레임워크 전환에서는 지원되지 않습니다. 프레임워크 전환에서 벗어나 Animator 및 AndroidX 전환을 대신 사용하세요.
  • 뒤로 탐색 예측 전환은 Android 14 이상을 실행하는 기기에서 지원되며 이전 버전과 호환되지 않습니다.
  • XML 장면으로 만든 전환도 지원됩니다. handleOnBackStarted에서 TransitionSeekControllercontrolDelayedTransition의 결과 대신 TransitionManager.createSeekController의 결과로 설정합니다.

추가 리소스