Platformlar arası gezinme etkinliklerini işlemek için soyut sınıfı NavigationEventHandler genişletebilirsiniz. Bu sınıf, gezinme hareketinin yaşam döngüsüne karşılık gelen yöntemler sağlar.
val myHandler = object: NavigationEventHandler<NavigationEventInfo>( initialInfo = NavigationEventInfo.None, isBackEnabled = true ) { override fun onBackStarted(event: NavigationEvent) { // Prepare for the back event } override fun onBackProgressed(event: NavigationEvent) { // Use event.progress for predictive animations } // This is the required method for final event handling override fun onBackCompleted() { // Complete the back event } override fun onBackCancelled() { // Cancel the back event } }
addHandler işlevi, işleyiciyi dağıtıcıya bağlar:
navigationEventDispatcher.addHandler(myHandler)
Yönlendiriciden işleyiciyi kaldırmak için myHandler.remove() işlevini çağırın:
myHandler.remove()
İşleyiciler önceliğe ve ardından yeniliğe göre çağrılır. Tüm PRIORITY_OVERLAY işleyicileri, herhangi bir PRIORITY_DEFAULT işleyicisinden önce çağrılır. Her öncelik grubunda işleyiciler, son eklenen ilk çağrılır (Last-In, First-Out - LIFO) sırasına göre çağrılır.
Jetpack Compose ile geri yakalama
Kitaplık, Jetpack Compose için dağıtıcı hiyerarşisini yönetmeye yönelik bir yardımcı composable sağlar.
NavigationBackHandler composable'ı, içeriği için bir NavigationEventHandler oluşturur ve bunu LocalNavigationEventDispatcherOwner'ye bağlar. Composable, ekrandan ayrıldığında kaynakları güvenli bir şekilde yöneterek göndericinin dispose() yöntemini otomatik olarak çağırmak için Compose'un DisposableEffect özelliğini kullanır.
@Composable public fun NavigationBackHandler( state: NavigationEventState<out NavigationEventInfo>, isBackEnabled: Boolean = true, onBackCancelled: () -> Unit = {}, onBackCompleted: () -> Unit, ){ }
Bu işlev, yerelleştirilmiş kullanıcı arayüzü alt ağaçlarında etkinlik işlemeyi hassas bir şekilde kontrol etmenizi sağlar.
@Composable fun HandlingBackWithTransitionState( onNavigateUp: () -> Unit ) { val navigationState = rememberNavigationEventState( currentInfo = NavigationEventInfo.None ) val transitionState = navigationState.transitionState // React to predictive back transition updates when (transitionState) { is NavigationEventTransitionState.InProgress -> { val progress = transitionState.latestEvent.progress // Use progress (0f..1f) to update UI during the gesture } is NavigationEventTransitionState.Idle -> { // Reset any temporary UI state if the gesture is cancelled } } NavigationBackHandler( state = navigationState, onBackCancelled = { // Called if the back gesture is cancelled }, onBackCompleted = { // Called when the back gesture fully completes onNavigateUp() } ) }
Bu örnekte, NavigationEventTransitionState kullanarak tahmin edilen geri gitme hareketi güncellemelerinin nasıl gözlemleneceği gösterilmektedir. progress değeri, NavigationBackHandler aracılığıyla tamamlama ve iptal işlemleri yapılırken geri hareketine yanıt olarak kullanıcı arayüzü öğelerini güncellemek için kullanılabilir.
Yazma sırasında geri hareketine veya kenarı kaydırma hareketine erişme
Şekil 1. NavigationEvent ve Compose ile oluşturulmuş bir tahmin edilen geri gitme animasyonu.
Kullanıcı geri kaydırırken ekranı canlandırmak için (a) NavigationEventTransitionState öğesinin InProgress olup olmadığını kontrol etmeniz ve (b) rememberNavigationEventState ile ilerleme ve kaydırma kenarı durumunu gözlemlemeniz gerekir:
progress: Kullanıcının ne kadar kaydırdığını gösteren0.0ile1.0arasındaki bir kayan nokta değeri.swipeEdge: Hareketin nerede başladığını gösteren bir tam sayı sabiti (EDGE_LEFTveyaEDGE_RIGHT).
Aşağıdaki snippet, ölçek ve kaydırma animasyonunun nasıl uygulanacağına dair basitleştirilmiş bir örnektir:
object Routes { const val SCREEN_A = "Screen A" const val SCREEN_B = "Screen B" } class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { var state by remember { mutableStateOf(Routes.SCREEN_A) } val backEventState = rememberNavigationEventState<NavigationEventInfo>(currentInfo = NavigationEventInfo.None) when (state) { Routes.SCREEN_A -> { ScreenA(onNavigate = { state = Routes.SCREEN_B }) } else -> { if (backEventState.transitionState is NavigationEventTransitionState.InProgress) { ScreenA(onNavigate = { }) } ScreenB( backEventState = backEventState, onBackCompleted = { state = Routes.SCREEN_A } ) } } } } } @Composable fun ScreenB( backEventState: NavigationEventState<NavigationEventInfo>, onBackCompleted: () -> Unit = {}, ) { val transitionState = backEventState.transitionState val latestEvent = (transitionState as? NavigationEventTransitionState.InProgress) ?.latestEvent val backProgress = latestEvent?.progress ?: 0f val swipeEdge = latestEvent?.swipeEdge ?: NavigationEvent.EDGE_LEFT if (transitionState is NavigationEventTransitionState.InProgress) { Log.d("BackGesture", "Progress: ${transitionState.latestEvent.progress}") } else if (transitionState is NavigationEventTransitionState.Idle) { Log.d("BackGesture", "Idle") } val animatedScale by animateFloatAsState( targetValue = 1f - (backProgress * 0.1f), label = "ScaleAnimation" ) val windowInfo = LocalWindowInfo.current val density = LocalDensity.current val maxShift = remember(windowInfo, density) { val widthDp = with(density) { windowInfo.containerSize.width.toDp() } (widthDp.value / 20f) - 8 } val offsetX = when (swipeEdge) { EDGE_LEFT -> (backProgress * maxShift).dp EDGE_RIGHT -> (-backProgress * maxShift).dp else -> 0.dp } NavigationBackHandler( state = backEventState, onBackCompleted = onBackCompleted, isBackEnabled = true ) Box( modifier = Modifier .offset(x = offsetX) .scale(animatedScale) ){ // Rest of UI } }