अलग-अलग प्लैटफ़ॉर्म पर नेविगेशन इवेंट मैनेज करने के लिए, ऐब्स्ट्रैक्ट क्लास 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 हैंडलर से पहले कॉल किया जाता है. हर प्राथमिकता वाले ग्रुप में, हैंडलर को लास्ट-इन, फ़र्स्ट-आउट (लाइफ़ो) क्रम में लागू किया जाता है. इसका मतलब है कि सबसे हाल ही में जोड़े गए हैंडलर को सबसे पहले कॉल किया जाता है.
Jetpack Compose की मदद से वापस जाने की सुविधा को इंटरसेप्ट करना
Jetpack Compose के लिए, यह लाइब्रेरी डिसपैचर के क्रम को मैनेज करने के लिए, यूटिलिटी कंपोज़ेबल उपलब्ध कराती है.
NavigationBackHandler कंपोज़ेबल, अपने कॉन्टेंट के लिए NavigationEventHandler बनाता है और उसे LocalNavigationEventDispatcherOwner से लिंक करता है. यह Compose के 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 के ज़रिए पूरा होने और रद्द होने की प्रोसेस को मैनेज किया जा सकता है.
Compose में, पीछे जाने के लिए किए जाने वाले जेस्चर या किनारे से स्वाइप करने की सुविधा को ऐक्सेस करना
पहली इमेज. NavigationEvent और Compose की मदद से बनाया गया प्रिडिक्टिव बैक ऐनिमेशन.
उपयोगकर्ता के पीछे की ओर स्वाइप करने पर स्क्रीन को ऐनिमेट करने के लिए, आपको ये काम करने होंगे: (a) यह देखना होगा कि NavigationEventTransitionState InProgress है या नहीं. (b) 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 } }