0% found this document useful (0 votes)
154 views

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
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
154 views

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
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