While trying to navigate from MapsScreen to SignupScreen in Jetpack Compose, although I see in logcat that SignUp is clicked,I am not able to navigate to SignupScreen. I have setup the navgraph and the composables. What is missing?
package com.example.bettehomes.presentation.mapscreens
import android.util.Log
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.example.bettehomes.presentation.composables.GeoMarkerTopBar
import com.example.bettehomes.navigation.Screens
@ExperimentalMaterial3Api
@Composable
fun MapsScreen(
snackbarHostState: SnackbarHostState,
navController: NavController,
onNavigateToSignupScreen: () -> Unit,
fetchLocationUpdates: () -> Unit
) {
Scaffold(
topBar = { GeoMarkerTopBar() },
content = { innerPadding ->
Box(modifier = Modifier.padding(innerPadding)) {
MapScreenContent(snackbarHostState, fetchLocationUpdates)
SnackbarHost(
hostState = snackbarHostState,
modifier = Modifier
.wrapContentHeight(Alignment.Bottom)
.align(Alignment.BottomCenter)
)
Box(modifier=Modifier.fillMaxSize(),contentAlignment = Alignment.TopCenter) {
AnnotatedClickableText(onNavigateToSignupScreen)
}
}
},
floatingActionButton = {
ExtendedFloatingActionButton(
modifier = Modifier
.padding(16.dp),
onClick = {
navController.navigate(Screens.GeoMarkerScreen.route)
},
icon = {
Icon(
Icons.Filled.Add,
contentDescription = "Create"
)
},
text = { Text("Mark Area") }
)
}
)
}
@Composable
fun AnnotatedClickableText(onNavigateToSignupScreen:() -> Unit) {
val annotatedText = buildAnnotatedString {
//append your initial text
withStyle(
style = SpanStyle(
color = Color.Gray,
)
) {
append("Don't have an account? ")
}
//Start of the pushing annotation which you want to color and make them clickable later
pushStringAnnotation(
tag = "SignUp",// provide tag which will then be provided when you click the text
annotation = "SignUp"
)
//add text with your different color/style
withStyle(
style = SpanStyle(
color = Color.Red,
)
) {
append("Sign Up")
}
// when pop is called it means the end of annotation with current tag
pop()
}
ClickableText(
text = annotatedText,
onClick = { run { onNavigateToSignupScreen }
annotatedText.getStringAnnotations(
tag = "SignUp",// tag which you used in the buildAnnotatedString
start = it,
end = it
)[0].let { annotation ->
//do your stuff when it gets clicked
Log.d("Clicked", annotation.item)
}
},
)
}
NavHost.kt
package com.example.bettehomes.navigation
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import com.example.bettehomes.data.home.HomeViewModel
import com.example.bettehomes.data.login.LoginViewModel
import com.example.bettehomes.data.signup.SignupViewModel
import com.example.bettehomes.presentation.GeoMarkerViewModel
import com.example.bettehomes.presentation.authscreens.HomeScreen
import com.example.bettehomes.presentation.authscreens.LoginScreen
import com.example.bettehomes.presentation.authscreens.SignUpScreen
import com.example.bettehomes.presentation.authscreens.TermsAndConditionsScreen
import com.example.bettehomes.presentation.mapscreens.GeoMarkerScreen
import com.example.bettehomes.presentation.mapscreens.MapsScreen
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppNavigation(
navController: NavHostController,
snackbarHostState: SnackbarHostState,
homeViewModel: HomeViewModel,
loginViewModel: LoginViewModel,
signUpViewModel:SignupViewModel,
geoMarkerViewModel: GeoMarkerViewModel,
fetchLocationUpdates: () -> Unit
) {
NavHost(navController=navController,startDestination = Screens.MapScreen.route) {
composable(Screens.MapScreen.route) {
MapsScreen(
snackbarHostState = snackbarHostState,
navController = navController,
onNavigateToSignupScreen = { navController.navigate(Screens.SignUpScreen.route)},
fetchLocationUpdates)
}
composable(Screens.SignUpScreen.route){
SignUpScreen(signUpViewModel)
}
composable(Screens.LoginScreen.route){
LoginScreen(loginViewModel)
}
composable(Screens.TermsAndConditionsScreen.route){
TermsAndConditionsScreen()
}
composable(Screens.HomeScreen.route){
HomeScreen(homeViewModel)
}
composable(Screens.GeoMarkerScreen.route){
GeoMarkerScreen(geoMarkerViewModel)
}
}
}
When you say onNavigateToSignupScreen
, you are just referencing a variable - it doesn't actually do anything.
Instead, if you want to invoke the lambda, you need to use onNavigateToSignupScreen()
(which is really just shorthand for what is actually going on - onNavigateToSignupScreen.invoke()
).