شما میتوانید کلاس انتزاعی 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)
برای حذف هندلر از dispatcher، تابع myHandler.remove() را فراخوانی کنید:
myHandler.remove()
هندلرها بر اساس اولویت و سپس بر اساس تازگی فراخوانی میشوند. همه هندلرهای PRIORITY_OVERLAY قبل از هر هندلر PRIORITY_DEFAULT فراخوانی میشوند. در هر گروه اولویت، هندلرها به ترتیب آخرین ورودی، اولین خروجی (LIFO) فراخوانی میشوند - هندلری که اخیراً اضافه شده است، ابتدا فراخوانی میشود.
رهگیری بازگشت با Jetpack Compose
برای Jetpack Compose، این کتابخانه یک ابزار composable برای مدیریت سلسله مراتب dispatcher ارائه میدهد.
کامپوننت NavigationBackHandler یک NavigationEventHandler برای محتوای خود ایجاد میکند و آن را به LocalNavigationEventDispatcherOwner پیوند میدهد. این کامپوننت از DisposableEffect کامپوننت برای فراخوانی خودکار متد dispose() در زمان خروج کامپوننت از صفحه استفاده میکند و منابع را با خیال راحت مدیریت میکند.
@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 ، مورد استفاده قرار گیرد.
در نوشتن، به ژست بازگشت یا کشیدن انگشت به لبه صفحه دسترسی پیدا کنید
شکل ۱. یک انیمیشن برگشتی پیشبینیکننده ساخته شده با NavigationEvent و Compose.
برای متحرکسازی صفحه نمایش در حالی که کاربر انگشت خود را به عقب میکشد، باید (الف) بررسی کنید که آیا NavigationEventTransitionState InProgress است یا خیر، و (ب) با استفاده از rememberNavigationEventState پیشرفت و وضعیت لبههای کشیدن انگشت را مشاهده کنید:
-
progress: یک عدد اعشاری از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) { 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 } }