JetpackCompose Navigation
JetpackCompose Navigation
Compose
Navigation
@alex_zhukovich
https://alexzh.com/
ANDROID
NAVIGATION
HISTORY INTENT
FRAGMENT
MANAGER JETPACK
NAVIGATION
INTENT FRAGMENT MANAGER JETPACK NAVIGATION
API 1 API
2008 11 20 1
Activity based
2011 9
navigation
INTENT FRAGMENT MANAGER JETPACK NAVIGATION
API API 11
1 2011 20 1
20 0 8 Fragment support
9
Fragment based
navigation
INTENT FRAGMENT MANAGER JETPACK NAVIGATION
API API
1 11 2019
20 0 8 2011 Fragment based navigation
Navigation Graph
NAVIGATION
USE
CASES
UPDATE PART OF THE SCREEN
SCREEN ➔ SCREEN
UPDATE PART OF THE SCREEN
SCREEN ➔ SCREEN
ACTIVITY
ACTIVITY FRAGMENT
COMPOSABLE
ACTIVITY FRAGMENT
FUNCTION
JETPACK COMPOSE
NAVIGATION
ANDROID APPS
ROUTING
NAVIGATION
GRAPHS
@Composable
fun Demo() {
Box(
conten = Alignment.Center,
tAlign
modifier = Modifier.fillMaxSize()
) {ment
val count = remember { mutableStateOf(42) }
Row {
Text(
text = "-",
modifier = Modifier.clickable {
count.value -= 1 - 42 +
}
)
Text(text = "${count.value}")
Text(
text = "+",
modifier = Modifier.clickable {
count.value += 1
}
)
}
}
}
@Composable
fun Demo() {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier.fillMaxSize()
) {
val count = remember
{ mutableStateOf(42) }
Row {
Text(
modifier
text = Modifier.clickable {
= "-",
count.value -= 1 - 42 +
}
)
Text(text = "${count.value}")
Text(
text = "+",
modifier = Modifier.clickable {
count.value += 1
}
)
}
}
}
@Composable
fun
BasketSuccessScreen( s
tate: BasketState,
externalRouter: Router,
addCoffeeDrink: (Long) -> Unit,
removeCoffeeDrink: (Long) -> Unit
) {
Column(
modifier = Modifier.fillMaxSize()
) { TopAppBar {
Text(
text = "Basket",
modifier = = 12.dp),
Modifier.padding(horizontal fontSize
) = 18.sp
}
PaymentInfo(
deliveryCosts = BigDecimal(5),
total = state.totalPrice,
currency = '€',
isPayButtonEnabled =
state.products.isNotEmpty(), onPayed = {
externalRouter.navigateTo("Success")
}
)
Spacer(modifier = Modifier.height(8.dp))
ProductList(
basketProducts = state.products,
onProductIncreased = removeCoffeeDrink,
onProductDecreased = addCoffeeDrink
)
}
}
ANDROID APPS
JETPACK NAVIGATION COMPOSE VIEW
EXISTING
APPS
FRAGMENTS
JETPACK COMPOSE @COMPOSABLE
NAVIGATION
NEW
APPS
FULL COMPOSABLE
NAVIGATION GRAPH
NavHost
NavHost(
navController,
startDestination = Screen.Destination1.route
) {
composable(“CoffeeDrinks”) { CoffeeDrinksScreen(...) }
composable(“Basket”) { BasketScreen(...) }
composable(“Profile”) { Destination1Screen(...) }
}
@Composable
public funNavHost(
NavGraphBuilder navController: NavHostController,
startDestination: String,
modifier: Modifier = Modifier,
route: String? = null,
builder: NavGraphBuilder.() ->
composable Unit
) {NavHost(
navController,
remember(route, startDestination, builder) {
navController.createGraph(
startDestination,
route,
builder
Add a NavDestination to )
},
the destination list modifier
)
}
@Composable
public funNavHost(
NavGraphBuilder navController: NavHostController,
startDestination: String,
modifier: Modifier = Modifier,
route: String? = null,
builder: NavGraphBuilder.() ->
composable Unit
) {NavHost(
navController,
remember(route, startDestination, builder) {
navController.createGraph(
startDestination,
route,
builder
Add a NavDestination to )
},
the destination list modifier
)
}
NavHost
NavGraph NavGraph
navigate
navigate
NavHost(
navController = tabsNavController,
startDestination = NavigationItem.CoffeeDrinks.route
) {
composable(“CoffeeDrinks”)
{ CoffeeDrinksScreen(...) }
composable(“Basket”) { BasketScreen(...) }
composable(“Profile”)
{ Destination1Screen(...) }
}
navController.navigate(“CoffeeDrinks”
)
ROUTING WITH PARAMS
NavHost(
navCo navController,
ntrol
startDestination = "coffeeDrinks"
) { ler =
composable(
route = "CoffeeDrinkDetails/{coffeeDrinkId}"
) {
CoffeeDrinkDetailsScreen( navCon
troller = navController,
coffeeDrinkId =
it.arguments?.getLong(“coffeeD
rinkId") ?: -1L
)
}
}
navController.navigate(“CoffeeDrinkDetails/$coffeeDrinkId”)
ROUTING WITH PARAMS
Intege
r
NavHost(
Float
navCo navController,
startDestination
ntrol = "coffeeDrinks"
)ler = Long
composable(
{ route = Boolean
arguments = listOf(
"CoffeeDrinkDetails/{coffeeDrinkId}",
navArgument("coffeeDrinkId") { String
type = NavType.LongType
} Resource
) reference
) { P arcelable
CoffeeDrinkDetailsScreen(
navController = navController, Serializable
coffeeDrinkId = it.arguments
?.getLong(“coffeeDrinkId") ?: -1L
Enum
)
}
}
DEEP LINKING AndroidManifest.xml
<application
...>
<activity
android:name=".MainActivity"
...>
<intent-filter>
...
<data
android:host="example.com"
android:scheme="https" />
</intent-filter>
</
activity
>
</
DEEP LINKING Compose
NavHost(
navCo tabsNavController,
startDestination
ntrol = Screen.CoffeeDrinks.route
) {ler =
composable(
route =
NavigationItem.CoffeeDrinkDetails.route,
arguments = listOf(
navArgument("coffeeDrinkId") { type =
NavType.LongType }
),
deepLinks = listOf(
navDeepLink {
uriPattern =
"$uri/CoffeeD
rinkDetails/c
offeeDrinkId=
{coffeeDrinkI
d}"
}
)
) {
CoffeeDrinkDetailsScreen( navControl
ROUTING TO EXTERNAL APP
@Composable
fun DemoScreen() {
val context = LocalContext.current
Button(
onCl
ick intent = Intent(
= { Intent.ACTION_VIEW,
val Uri.parse("geo:52.3676, 4.9041”)
).apply {
setPackage("com.google.android.a
pps.maps")
}
} context.startActivity(intent)
) {
Text(
text = "Open map"
)
}
}
NAVIGATION OPTIONS Navigate
A B C
A
NAVIGATION OPTIONS Navigate
A B C
navigate
A
NAVIGATION OPTIONS Navigate
A B C
navigate
A
NAVIGATION OPTIONS Navigate
A B C A
navigate A
NAVIGATION OPTIONS PopUpTo
A B C
A
NAVIGATION OPTIONS PopUpTo
A B C
navigate
A
NAVIGATION OPTIONS PopUpTo
A B C
navigate
A
NAVIGATION OPTIONS PopUpTo
A B C
C
A
navigate(“A”) {
popUpTo(“A”)
}
NAVIGATION OPTIONS PopUpTo
A B C
A
NAVIGATION OPTIONS PopUpTo & Inclusive
A B C
A
NAVIGATION OPTIONS PopUpTo & Inclusive
A B C
navigate
A
NAVIGATION OPTIONS PopUpTo & Inclusive
A B C
navigate
A
NAVIGATION OPTIONS PopUpTo & Inclusive
A B C
C
A
navigate(“A”) {
popUpTo(“A”) { inclusive = true }
}
NAVIGATION OPTIONS PopUpTo & Inclusive
A B C
navigate(“A”) {
popUpTo(“A”) { inclusive = true }
}
APPLICATION
SCREEN BOTTOM NAVIGATION
DIFFERENT GRAPHS
class MainActivity : ComponentActivity() {
NavHost( fun
navController = navController, createRouter(
startDestination = Screen.Home.route block: (String) -> Unit
) { ): Router = object :
composable(Screen.Home.route) { Router {
HomeScreen(
createRouter { route -> }
override fun navigateTo(route: String) {
navController.navigate(route) }
} block.invoke(route)
)
}
...
}
}
}
}
}
DIFFERENT GRAPHS
class MainActivity : ComponentActivity() {
NavHost(
navController = navController,
startDestination = Screen.Home.route
) {
composable(Screen.Home.route) {
HomeScreen(
createRouter { route ->
navController.navigate(rout
e)
}
)
}
...
}
}
}
}
}
@Composable
fun
class MainActivity : ComponentActivity() {
CoffeeDrinksScreen( navigateToCoffeeDrinkDet
override fun onCreate(savedInstanceState: Bundle?) {
ails: (Long)
viewModel: -> Unit,
CoffeeDrinksViewModel = CoffeeDrinksViewModel()
) {
super.onCreate(savedInstanceState
viewModel.loadCoffeeDrinks() )
setContent {
viewModel.uiState.observeAsState OrderCoffeeTheme {
( initial = UiState.Loading val navController = rememberNavController()
).value.let { uiState ->
when (uiState) { NavHost(
is UiState.Loading -> { navController = navController,
... startDestination = Screen.Home.route
} ) {
is UiState.Success -> {
... composable(Screen.Home.route)
CoffeeDrinkList( {
items = uiState.data, CoffeeDrinksScreen(
navigateToCoffeeDrinkDetails = {
onCoffeeDrink = navController.navigate(
navigateToCoffeeDrinkDetails, CoffeeDrinkDetails
onCoffeeDrinkCountIncreased = { .createRoute(it)
viewModel.addCoffeeDrink(it) )
}, }
onCoffeeDrinkCountDecreased = { )
viewModel.removeCoffeeDrink(it) }
) }
} ...
is UiState.Error -> { }
... }
} }
}
}
}
}
}
@Composable
fun
class MainActivity : ComponentActivity() {
CoffeeDrinksScreen( navigateToCoffeeDrinkDet
override fun onCreate(savedInstanceState: Bundle?) {
ails: (Long)
viewModel: -> Unit,
CoffeeDrinksViewModel = CoffeeDrinksViewModel()
) {
super.onCreate(savedInstanceState
viewModel.loadCoffeeDrinks() )
setContent {
viewModel.uiState.observeAsState OrderCoffeeTheme {
( initial = UiState.Loading val navController = rememberNavController()
).value.let { uiState ->
when (uiState) { NavHost(
is UiState.Loading -> { navController = navController,
... startDestination = Screen.Home.route
} ) {
is UiState.Success -> {
... composable(Screen.Home.route)
CoffeeDrinkList( {
items = uiState.data, CoffeeDrinksScreen(
navigateToCoffeeDrinkDetails = {
onCoffeeDrink = navController.navigate(
navigateToCoffeeDrinkDetails, CoffeeDrinkDetails
onCoffeeDrinkCountIncreased = { .createRoute(it)
viewModel.addCoffeeDrink(it) )
}, }
onCoffeeDrinkCountDecreased = { )
viewModel.removeCoffeeDrink(it) }
) }
} ...
is UiState.Error -> { }
... }
} }
}
}
}
}
}
THANK YOU
FOR LISTENING!
@alex_zhukovich
alex-zhukovich
https://alexzh.com/