0% found this document useful (0 votes)
200 views58 pages

JetpackCompose Navigation

The document discusses the history and evolution of navigation in Android apps. It covers navigation using Intents starting from API 1 in 2008, the introduction of fragments and fragment-based navigation in API 11 in 2011, and the Jetpack Navigation component introduced in 2019. It then demonstrates how navigation can be implemented using the Jetpack Navigation component in a Compose app with composable destinations and navigation graphs. Key routing concepts like NavHost, NavController, and navigating between destinations are also explained.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
200 views58 pages

JetpackCompose Navigation

The document discusses the history and evolution of navigation in Android apps. It covers navigation using Intents starting from API 1 in 2008, the introduction of fragments and fragment-based navigation in API 11 in 2011, and the Jetpack Navigation component introduced in 2019. It then demonstrates how navigation can be implemented using the Jetpack Navigation component in a Compose app with composable destinations and navigation graphs. Key routing concepts like NavHost, NavController, and navigating between destinations are also explained.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 58

Jetpack

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

Destination Destination Destination

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

Destination Destination Destination Destination


NavHost(
navController = navController,
startDestination = "CoffeeDrinks"
) {
composable("CoffeeDrinks") {
CoffeeDrinksScreen( nav
igateToDetails = {
navController.navigat
e("CoffeeDrinkDeta
ils")
},
navigateToBasket =
{ navController.navigate(“Bask
et")
}
)
}
composable("CoffeeDrinkDetails") {
CoffeeDrinkDetails()
}
composable("Basket") {
Basket()
}
}
NavHost(
navController = navController,
startDestination = "CoffeeDrinks"
) {
composable("CoffeeDrinks") {
CoffeeDrinksScreen( nav
igateToDetails = {
navController.navigat
e("CoffeeDrinkDeta
ils")
},
navigateToBasket =
{ navController.navigate(“Bask
et")
}
)
}
composable("CoffeeDrinkDetails") {
CoffeeDrinkDetails()
}
composable("Basket") {
Basket()
}
}
NavHost(
navController = navController,
startDestination = "CoffeeDrinks"
) {
composable("CoffeeDrinks") {
CoffeeDrinksScreen( nav
igateToDetails = {
navController.navigat
e("CoffeeDrinkDeta
ils")
},
navigateToBaske
t =
{ navContro
ller.navigat
e(“Basket")
}
)
}
composable("CoffeeDrinkDetails
") {
CoffeeDrinkDetails()
}
composable("Basket") {
Basket()
}
NavController

navigate

Try to find a destination in the


graph
public fun navigate(
route: String,
builder:
) {NavOptionsBuilder
Back stack modification based on
.() -> Unit
navigate(route, navOptions(builder))
NavOptions
}

Add a new/existing NavBackStackEntry to the


back stack

Update Back stack


lifecycle
NavController

navigate

Try to find a destination in the


graph
public fun navigate(
route: String,
builder:
) {NavOptionsBuilder
Back stack modification based on
.() -> Unit
navigate(route, navOptions(builder))
NavOptions
}

Add a new/existing NavBackStackEntry to the


back stack

Update Back stack


lifecycle
ROUTING
DEMO
TIME
ROUTING

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

const val COFFEE_DRINKS_KEY = "CoffeeDrinks"


NavHost( const val COFFEE_DRINK_DETAILS_KEY =
navCo navController, "CoffeeDrinkDetails"
ntrol
startDestination = "coffeeDrinks" const val FULL_COFFEE_DRINK_DETAILS_KEY
)ler = =
“CoffeeDrinkDetails/{coffeeDrinkId}"
{ route = Screen.CoffeeDrinkDetails.route
) composable(
{
CoffeeDrinkDetailsScreen( navCon sealed class Screen(val route: String) {
troller = navController,
coffeeDrinkId = it.arguments object CoffeeDrinks :
?.getLong(“coffeeDrinkId") ?: Screen(COFFEE_DRINKS_KEY)
-1L
) object CoffeeDrinkDetails:
} Screen(FULL_COFFEE_DRINK_DETAILS_KEY) {
} fun createRoute(coffeeDrinkId: Long) =
"$COFFEE_DRINK_DETAILS_KEY/$coffeeDrinkId"
}
}
navController.navigate( Screen.CoffeeDrinkDe
tails.createRoute(42L)
)
ROUTING WITH TYPED 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>
...

<action android:name="android.intent.action.VIEW" />


<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<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() {

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState) interface Router {
setContent {
OrderCoffeeTheme {
fun navigateTo(route: String)
val navController =
rememberNavController()
}

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() {

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
setContent {
OrderCoffeeTheme {
val navController = rememberNavController()

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/

You might also like