میتوانید کلاس انتزاعی NavigationEventHandler را برای مدیریت رویدادهای پیمایش در پلاتفرمهای مختلف گسترش دهید. این کلاس روشهایی را ارائه میدهد که با
چرخه حیات اشاره پیمایش مطابقت دارد.
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 کنترلکننده را به توزیعکننده متصل میکند:
navigationEventDispatcher.addHandler(myHandler)
برای برداشتن گرداننده از توزیعکننده، myHandler.remove() را فراخوانی کنید:
myHandler.remove()
گردانندهها براساس اولویت و سپس براساس تازگی فراخوانده میشوند. همه
گردانندههای PRIORITY_OVERLAY قبلاز هر گرداننده
PRIORITY_DEFAULT فراخوانده میشوند. در هر گروه اولویت، کنترلکنندهها بهترتیب «آخرین ورودی، اولین خروجی» (LIFO) فراخوانی میشوند — کنترلکنندهای که اخیراً اضافه شده است ابتدا فراخوانی میشود.
رهگیری برگشت با Jetpack Compose
برای Jetpack Compose، کتابخانه یک ابزار کمکی قابلترکیب برای مدیریت سلسلهمراتب توزیعکننده ارائه میدهد.
NavigationBackHandler composable یک NavigationEventHandler برای
محتوای خود ایجاد میکند و آن را به LocalNavigationEventDispatcherOwner پیوند میدهد. این ویژگی از
DisposableEffect Compose برای فراخوانی خودکار روش dispose()
توزیعکننده هنگام خروج composable از صفحه استفاده میکند و منابع را بهطور ایمن مدیریت میکند.
@Composable public fun NavigationBackHandler( state: NavigationEventState<out NavigationEventInfo>, isBackEnabled: Boolean = true, onBackCancelled: () -> Unit = {}, onBackCompleted: () -> Unit, ){ }
این تابع به شما امکان میدهد مدیریت رویداد را بهطور دقیق در زیردرختهای واسط کاربر بومیسازیشده کنترل کنید.
@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() } ) }
این مثال نشان میدهد که چگونه میتوان بااستفاده از
NavigationEventTransitionState بهروزرسانیهای اشاره برگشت پیشگویانه را مشاهده کرد. از مقدار progress میتوان برای بهروزرسانی عناصر میانای کاربر در پاسخ به اشاره برگشت استفاده کرد، درحالیکه تکمیل و لغو ازطریق NavigationBackHandler مدیریت میشود.
دسترسی به اشاره برگشت یا لبه تند کشیدن در Compose
شکل ۱. پویانمایی اشاره برگشت پیشگویانه ساختهشده با NavigationEvent و Compose.
برای پویانمایی کردن صفحه هنگام تند کشیدن کاربر به عقب، باید (الف) بررسی کنید که آیا
NavigationEventTransitionState InProgress است یا نه، و (ب)
پیشرفت و وضعیت لبه تند کشیدن را با rememberNavigationEventState مشاهده کنید:
-
progress: یک Float از0.0تا1.0که نشان میدهد کاربر چقدر تند کشیده است. -
swipeEdge: ثابت عدد صحیحی (EDGE_LEFTیاEDGE_RIGHT) که نشان میدهد اشاره از کجا شروع شده است.
تکهکد زیر نمونهای سادهشده از نحوه پیادهسازی پویانمایی مقیاس و جابهجایی است:
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) { NavigationEvent.EDGE_LEFT -> (backProgress * maxShift).dp NavigationEvent.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 } }