droidknights / DroidKnightsApp

국내 최대 규모 안드로이드 컨퍼런스 드로이드나이츠 앱
https://www.droidknights.dev
258 stars 71 forks source link

fix: 탭 전환 시 화면 오버래핑 되는 현상 수정 #336

Closed Songgyubin closed 2 weeks ago

Songgyubin commented 1 month ago

Overview (Required)

jetpack compose navigation에 대한 버전업을 했습니다. beta02-> beta06

탭 간 이동 시 화면이 overlap 되는 현상이 있습니다. 이 이슈는 jetpack compose navigation 2.8.0-beta03까지 나오는 버그이고, 현재 드로이드 나이츠 앱에서는 beta02 버전을 사용하고 있어서 생기는 문제입니다. 동일한 버그에 대한 제기된 이슈 내용도 있습니다.

navigation release note를 보시면 beta04 버전에 predictive back gesture cancellation(예측 백 제스처 취소)로 인한 애니메이션에 발생한 문제를 해결한 내용이 있는데요.

스크린샷 2024-08-16 오후 1 06 40

릴리즈 노트 상으로는 제기한 버그와 다른 수정사항이지만, 직접 확인 결과 화면이 overlap 되는 현상이 해결되어 문의를 남겼고 predictive back gesture cancellation(예측 백 제스처 취소)로 인한 애니메이션에 발생한 문제와 동일한 문제로 판단되어 함께 수정되었다는 답변을 받았습니다. 스크린샷 2024-08-16 오후 12 12 17

compose navigation의 현재 최신 버전은 beta07이지만, 해당 버전은 compile sdk 버전이 35이상일 경우에 사용가능하기에 beta06으로 버전업하였습니다.

Links

Screenshot

Before After
github-actions[bot] commented 1 month ago
Snapshot diff report vs base branch: main File name Image
KnightsAppTest.check
StartupShot_compare.
png
KnightsAppTest.check
MediumTabletLaunchSh
ot_compare.png
github-actions[bot] commented 1 month ago

Test Results

20 tests   20 :white_check_mark:  20s :stopwatch: 11 suites   0 :zzz: 11 files     0 :x:

Results for commit d3da5ac7.

Songgyubin commented 1 month ago

compose navigation 애니메이션에 관한 수정 코드 내용입니다. https://android-review.googlesource.com/c/platform/frameworks/support/+/3138255/5/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHost.kt#34

val transition = rememberTransition(transitionState, label = "entry")

        if (inPredictiveBack) {
            LaunchedEffect(progress) {
                val previousEntry = currentBackStack[currentBackStack.size - 2]
                transitionState.seekTo(progress, previousEntry)
            }
        } else {
            LaunchedEffect(backStackEntry) {
                // This ensures we don't animate after the back gesture is cancelled and we
                // are already on the current state
                if (transitionState.currentState != backStackEntry) {
                    transitionState.animateTo(backStackEntry)
                } else {
                    // convert from nanoseconds to milliseconds
                    val totalDuration = transition.totalDurationNanos / 1000000
                    // When the predictive back gesture is cancel, we need to manually animate
                    // the SeekableTransitionState from where it left off, to zero and then
                    // snapTo the final position.
                    animate(
                        transitionState.fraction,
                        0f,
                        animationSpec = tween((transitionState.fraction * totalDuration).toInt())
                    ) { value, _ ->
                        this@LaunchedEffect.launch {
                            if (value > 0) {
                                // Seek the original transition back to the currentState
                                transitionState.seekTo(value)
                            }
                            if (value == 0f) {
                                // Once we animate to the start, we need to snap to the right state.
                                transitionState.snapTo(backStackEntry)
                            }
                        }
                    }
                }
            }
        }