1
+ package com.smarttoolfactory.tutorial3_1navigation
2
+
3
+ import android.annotation.SuppressLint
4
+ import androidx.compose.animation.AnimatedContentTransitionScope.SlideDirection
5
+ import androidx.compose.animation.core.tween
6
+ import androidx.compose.foundation.background
7
+ import androidx.compose.foundation.clickable
8
+ import androidx.compose.foundation.layout.Arrangement
9
+ import androidx.compose.foundation.layout.Column
10
+ import androidx.compose.foundation.layout.PaddingValues
11
+ import androidx.compose.foundation.layout.Row
12
+ import androidx.compose.foundation.layout.Spacer
13
+ import androidx.compose.foundation.layout.fillMaxSize
14
+ import androidx.compose.foundation.layout.fillMaxWidth
15
+ import androidx.compose.foundation.layout.padding
16
+ import androidx.compose.foundation.layout.width
17
+ import androidx.compose.foundation.rememberScrollState
18
+ import androidx.compose.foundation.verticalScroll
19
+ import androidx.compose.material3.Button
20
+ import androidx.compose.material3.Checkbox
21
+ import androidx.compose.material3.Scaffold
22
+ import androidx.compose.material3.Text
23
+ import androidx.compose.runtime.Composable
24
+ import androidx.compose.runtime.collectAsState
25
+ import androidx.compose.runtime.getValue
26
+ import androidx.compose.runtime.mutableStateOf
27
+ import androidx.compose.runtime.remember
28
+ import androidx.compose.runtime.setValue
29
+ import androidx.compose.ui.Alignment
30
+ import androidx.compose.ui.Modifier
31
+ import androidx.compose.ui.graphics.Color
32
+ import androidx.compose.ui.tooling.preview.Preview
33
+ import androidx.compose.ui.unit.dp
34
+ import androidx.navigation.NavBackStackEntry
35
+ import androidx.navigation.NavController
36
+ import androidx.navigation.compose.NavHost
37
+ import androidx.navigation.compose.composable
38
+ import androidx.navigation.compose.rememberNavController
39
+
40
+ @Preview
41
+ @Composable
42
+ fun Tutorial2Screen () {
43
+ val navController = rememberNavController()
44
+
45
+ Scaffold { innerPadding: PaddingValues ->
46
+ NavHost (
47
+ modifier = Modifier
48
+ .padding(innerPadding)
49
+ .fillMaxSize(),
50
+ navController = navController,
51
+ startDestination = RouteA ,
52
+ enterTransition = {
53
+ slideIntoContainer(
54
+ towards = SlideDirection .Start ,
55
+ animationSpec = tween(700 )
56
+ )
57
+ },
58
+ exitTransition = {
59
+ slideOutOfContainer(
60
+ towards = SlideDirection .End ,
61
+ animationSpec = tween(700 )
62
+ )
63
+ },
64
+ popEnterTransition = {
65
+ slideIntoContainer(
66
+ towards = SlideDirection .Start ,
67
+ animationSpec = tween(700 )
68
+ )
69
+ },
70
+ popExitTransition = {
71
+ slideOutOfContainer(
72
+ towards = SlideDirection .End ,
73
+ animationSpec = tween(700 )
74
+ )
75
+ }
76
+ ) {
77
+ composable<RouteA > {
78
+ RouteAScreen (navController)
79
+ }
80
+
81
+ composable<RouteB > {
82
+ RouteBScreen (navController)
83
+ }
84
+
85
+ composable<RouteC > {
86
+ RouteCScreen (navController)
87
+ }
88
+
89
+ composable<RouteD > {
90
+ RouteDScreen (navController)
91
+ }
92
+ }
93
+ }
94
+ }
95
+
96
+ @Composable
97
+ private fun RouteAScreen (navController : NavController ) {
98
+ RouteScreen (
99
+ modifier = Modifier .background(Color .White ),
100
+ title = " RouteAScreen" ,
101
+ navController = navController
102
+ )
103
+ }
104
+
105
+ @Composable
106
+ private fun RouteBScreen (navController : NavController ) {
107
+ RouteScreen (
108
+ modifier = Modifier .background(Color .Cyan ),
109
+ title = " RouteBScreen" ,
110
+ navController = navController
111
+ )
112
+ }
113
+
114
+ @Composable
115
+ private fun RouteCScreen (navController : NavController ) {
116
+ RouteScreen (
117
+ modifier = Modifier .background(Color .Yellow ),
118
+ title = " RouteCScreen" ,
119
+ navController = navController
120
+ )
121
+ }
122
+
123
+ @Composable
124
+ private fun RouteDScreen (navController : NavController ) {
125
+ RouteScreen (
126
+ modifier = Modifier .background(Color .Green ),
127
+ title = " RouteDScreen" ,
128
+ navController = navController
129
+ )
130
+ }
131
+
132
+ @SuppressLint(" RestrictedApi" )
133
+ @Composable
134
+ private fun RouteScreen (
135
+ modifier : Modifier = Modifier ,
136
+ title : String ,
137
+ navController : NavController ,
138
+ ) {
139
+
140
+ var popUpToInclusive by remember {
141
+ mutableStateOf(false )
142
+ }
143
+
144
+ var isSingleTop by remember {
145
+ mutableStateOf(false )
146
+ }
147
+
148
+ Column (
149
+ modifier = modifier
150
+ .fillMaxSize()
151
+ .padding(16 .dp),
152
+ verticalArrangement = Arrangement .spacedBy(8 .dp)
153
+ ) {
154
+
155
+
156
+ Text (title)
157
+
158
+
159
+ var popUpToRoute by remember { mutableStateOf<Any ?>(null ) }
160
+
161
+
162
+ ExposedSelectionMenu (title = " PopUpTo" ,
163
+ index = when (popUpToRoute) {
164
+ null -> 0
165
+ RouteA -> 1
166
+ RouteB -> 2
167
+ RouteC -> 3
168
+ else -> 4
169
+ },
170
+ options = listOf (" no popUpTo" , " RouteA" , " RouteB" , " RouteC" , " RouteD" ),
171
+ onSelected = {
172
+ popUpToRoute = when (it) {
173
+ 0 -> null
174
+ 1 -> RouteA
175
+ 2 -> RouteB
176
+ 3 -> RouteC
177
+ else -> RouteD
178
+ }
179
+ }
180
+ )
181
+
182
+ Row {
183
+ CheckBoxWithText (
184
+ title = " popUpToInclusive" ,
185
+ enabled = popUpToRoute != null ,
186
+ checked = popUpToInclusive
187
+ ) {
188
+ popUpToInclusive = it
189
+ }
190
+
191
+ Spacer (Modifier .width(8 .dp))
192
+
193
+ CheckBoxWithText (
194
+ title = " singleTop" ,
195
+ checked = isSingleTop
196
+ ) {
197
+ isSingleTop = it
198
+ }
199
+ }
200
+
201
+ NavigationButton (
202
+ navController = navController,
203
+ title = " RouteA" ,
204
+ targetRoute = RouteA ,
205
+ popUpToRoute = popUpToRoute,
206
+ popUpToInclusive = popUpToInclusive,
207
+ singleTop = isSingleTop
208
+ )
209
+
210
+ NavigationButton (
211
+ navController = navController,
212
+ title = " RouteB" ,
213
+ targetRoute = RouteB ,
214
+ popUpToRoute = popUpToRoute,
215
+ popUpToInclusive = popUpToInclusive,
216
+ singleTop = isSingleTop
217
+ )
218
+
219
+ NavigationButton (
220
+ navController = navController,
221
+ title = " RouteC" ,
222
+ targetRoute = RouteC ,
223
+ popUpToRoute = popUpToRoute,
224
+ popUpToInclusive = popUpToInclusive,
225
+ singleTop = isSingleTop
226
+ )
227
+
228
+ NavigationButton (
229
+ navController = navController,
230
+ title = " RouteD" ,
231
+ targetRoute = RouteD ,
232
+ popUpToRoute = popUpToRoute,
233
+ popUpToInclusive = popUpToInclusive,
234
+ singleTop = isSingleTop
235
+ )
236
+
237
+ val backStack: List <NavBackStackEntry > by navController.currentBackStack.collectAsState()
238
+
239
+ Column (
240
+ modifier = Modifier .verticalScroll(rememberScrollState())
241
+ ) {
242
+ backStack.reversed().forEach {
243
+ Text (
244
+ text = it.destination.route ? : it.destination.displayName,
245
+ modifier = Modifier .fillMaxWidth()
246
+ )
247
+ }
248
+ }
249
+ }
250
+ }
251
+
252
+ @Composable
253
+ private fun NavigationButton (
254
+ navController : NavController ,
255
+ title : String ,
256
+ targetRoute : Any ,
257
+ popUpToRoute : Any? = null,
258
+ popUpToInclusive : Boolean ,
259
+ singleTop : Boolean ,
260
+ ) {
261
+ Button (
262
+ modifier = Modifier .fillMaxWidth(),
263
+ onClick = {
264
+ navController.navigate(
265
+ route = targetRoute
266
+ ) {
267
+ popUpToRoute?.let {
268
+ popUpTo(
269
+ route = it
270
+ ) {
271
+ inclusive = popUpToInclusive
272
+ }
273
+ }
274
+
275
+ launchSingleTop = singleTop
276
+ }
277
+ }
278
+ ) {
279
+ Text (" Navigate to $title " )
280
+ }
281
+ }
282
+
283
+ @Composable
284
+ private fun CheckBoxWithText (
285
+ modifier : Modifier = Modifier ,
286
+ title : String ,
287
+ enabled : Boolean = true,
288
+ checked : Boolean ,
289
+ onCheckChange : (Boolean ) -> Unit ,
290
+ ) {
291
+ Row (
292
+ modifier = modifier
293
+ .clickable(
294
+ enabled = enabled
295
+ ) {
296
+ onCheckChange(checked.not ())
297
+ }
298
+ .padding(8 .dp),
299
+ verticalAlignment = Alignment .CenterVertically
300
+ ) {
301
+ Checkbox (checked = checked, onCheckedChange = null , enabled = enabled)
302
+ Spacer (Modifier .width(16 .dp))
303
+ Text (title)
304
+ }
305
+ }
0 commit comments