How stop BottomSheet from Overlaying BottomNavBar (with Jetpack Compose) - kotlin

This is my first time using the BottomSheet.
I follow a tutorial and implemented the bottomsheet in a code with bottomnavbar. This was the result. {The bottomsheet overlaps the bottomnavbar, when it is collapsed}
As you can see the bottomsheet overlays the bottomnavbar.
Here's the code of the bottomSheet
#SuppressLint("UnusedMaterialScaffoldPaddingParameter")
#OptIn(ExperimentalMaterialApi::class)
#Composable
fun BottomSheetLayout() {
val bottomSheetItems = listOf(
BottomSheetItem(title = "Notification", icon = Icons.Default.Notifications),
...
)
val bottomSheetScaffoldState = rememberBottomSheetScaffoldState(
bottomSheetState = BottomSheetState(BottomSheetValue.Collapsed)
)
val coroutineScope = rememberCoroutineScope()
BottomSheetScaffold(
scaffoldState = bottomSheetScaffoldState,
sheetShape = RoundedCornerShape(topEnd = 30.dp),
sheetContent = {
Column(
content = {
Spacer(modifier = Modifier.padding(16.dp))
Text(
text = "Create New",
modifier = Modifier
.fillMaxWidth(),
textAlign = TextAlign.Center,
fontWeight = FontWeight.Bold,
fontSize = 21.sp,
color = Color.White
)
LazyVerticalGrid(
//cells = GridCells.Fixed(3),
columns = GridCells.Fixed(3)
) {
items(bottomSheetItems.size, itemContent = {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxWidth()
.padding(top = 24.dp)
.clickable {
},
) {
Spacer(modifier = Modifier.padding(8.dp))
Icon(
bottomSheetItems[it].icon,
bottomSheetItems[it].title,
tint = Color.White
)
Spacer(modifier = Modifier.padding(8.dp))
Text(text = bottomSheetItems[it].title, color = Color.White)
}
})
}
}, modifier = Modifier
.fillMaxWidth()
.height(350.dp)
//.background(MaterialTheme.colors.primary)
.background(
brush = Brush.linearGradient(colors = listOf(MaterialTheme.colors.primary, Color.White)
)
)
.padding(16.dp)
)
},
) {
Column(modifier = Modifier.fillMaxSize()) {
Button(
modifier = Modifier
.padding(20.dp),
onClick = {
coroutineScope.launch {
if (bottomSheetScaffoldState.bottomSheetState.isCollapsed) {
bottomSheetScaffoldState.bottomSheetState.expand()
} else {
bottomSheetScaffoldState.bottomSheetState.collapse()
}
}
}
) {
Text(
text = "Click to show Bottom Sheet"
)
}
}
}
}
Thanks for your help in advance.
I'd also appreciate any tip and advice about the bottomSheet, thanks again.

Related

how do I pass cursor from one textfield to other textfield in jetpack compose?

I have two textfields and the user will enter their weight and target weight. When the user clicks on the target weight, a picker appears and the user chooses his weight from there. If user selects his weight and presses the OK button, I want it to automatically switch to the target weight textfield.
hear is my code
I am sharing example textfield
Column(modifier = Modifier.fillMaxWidth()) {
TextField(
value = viewModel.defaultWeightValue.value ,
modifier = Modifier
.fillMaxWidth()
.padding(5.dp),
onValueChange = { viewModel.currentWeight.value = it },
label = { Text(text = "current weight (kg)") },
shape = RoundedCornerShape(5.dp),
colors = TextFieldDefaults.textFieldColors(
textColor = Grey2,
disabledTextColor = Color.Transparent,
backgroundColor = Grey3,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent,
),
interactionSource = remember { MutableInteractionSource() }
.also { interactionSource ->
LaunchedEffect(interactionSource) {
interactionSource.interactions.collect {
if (it is PressInteraction.Press) {
// works like onClick
viewModel.isUserClickTxtField.value = true
}
}
}
}
)
TextField(
value = viewModel.targetWeight.value,
modifier = Modifier
.fillMaxWidth()
.padding(5.dp),
onValueChange = { viewModel.targetWeight.value = it },
label = { Text(text = "target weight (kg)") },
shape = RoundedCornerShape(5.dp),
colors = TextFieldDefaults.textFieldColors(
textColor = Grey2,
disabledTextColor = Color.Transparent,
backgroundColor = Grey3,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent,
focusedLabelColor = DefaultDYTColor
)
)
}
DYTLoginAndContinueButton(
text = "continue",
navController,
Screen.SignUpFourthScreen.route
)
}
if (viewModel.isUserClickTxtField.value) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Bottom
) {
Row(
modifier = Modifier
.fillMaxWidth()
.background(Color.Gray),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
InfiniteNumberPicker(
modifier = Modifier.width(60.dp),
list = viewModel.weight,
firstIndex = 0,
onSelect = {
viewModel.weightPickerState.value = it
}
)
Text(text = "kg")
InfiniteNumberPicker(
modifier = Modifier.width(60.dp),
list = viewModel.gram,
firstIndex = 0,
onSelect = {
viewModel.grPickerState.value = it
}
)
Text(text = "gram")
}
Row(
modifier = Modifier
.fillMaxWidth()
.height(IntrinsicSize.Min)
.background(Color.Gray)
.padding(start = 0.dp, top = 15.dp, end = 0.dp, bottom = 15.dp),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "cancel",
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
color = DefaultDYTColor,
modifier = Modifier
.padding(8.dp)
.clickable {
viewModel.isUserClickTxtField.value = false
})
Divider(
color = Color.White,
modifier = Modifier
.padding(8.dp)
.fillMaxHeight() //fill the max height
.width(1.dp)
)
TextButton(onClick = {
viewModel.isUserClickTxtField.value = false
viewModel.defaultWeightValue.value = "${viewModel.weightPickerState.value} ${viewModel.grPickerState.value}"
}) {
Text(
text = "Okey",
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
color = DefaultDYTColor,
modifier = Modifier.padding(8.dp))
}
}
}
}
if user click textfield viewModel.isUserClickTxtField.value is true and picker pops up for user. if user click Okey button in picker that means user selected his weight on picker. I want to switch other textfield automatically how can I do that ?
You can use the solution provided by #bylazy or you can use the focusProperties modifier to specify the next/previous item for each TextField or composable in your screen
Then simply use the focusManager.moveFocus method to move the focus:
focusManager.moveFocus(FocusDirection.Next)
Something like:
val (item1, item2) = remember { FocusRequester.createRefs() }
val focusManager = LocalFocusManager.current
TextField(
value = text,
onValueChange = {text = it},
Modifier
.focusRequester(item1)
.focusProperties {
next = item2
right = item2
}
)
Button(
onClick = { focusManager.moveFocus(FocusDirection.Next) }
) { Text("OK") }
TextField(
value = text,
onValueChange = {text = it},
Modifier
.focusRequester(item2)
)
In your 1st TextField you can also add the keyboardActions attribute to move the focus clicking Done in the field.
TextField(
value = text,
onValueChange = {text = it},
Modifier
.focusRequester(item1)
.focusProperties {
next = item2
right = item2
},
keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(
onDone = { focusManager.moveFocus(FocusDirection.Next) }
)
)
Create and remember FocusRequester:
val focusRequester = remember { FocusRequester() }
Add this FocusRequester to the target TextField with modifier:
modifier = Modifier.focusRequester(focusRequester)
Use this code to request focus (cursor):
focusRequester.requestFocus()

add scroll - jetpack compose

I need to add a scroll to a page.
but i get this error: Vertically scrollable component was measured with an infinity maximum height constraints, which is disallowed.
I do have Lazy Column inside a big column.. and I think that is the problem.
but i need the whole page to scroll.
here is my code:
#Composable
fun ContactDetails(contactViewModel: ContactViewModel, contactId: String?) {
val contact = contactViewModel.getContactById(contactId)
val optionsScrollState = rememberScrollState()
Column(
modifier = Modifier
.fillMaxWidth()
.verticalScroll(state = optionsScrollState),
horizontalAlignment = Alignment.Start
) {
Row(
modifier = Modifier
.fillMaxWidth()
.height(350.dp)
) {
Card(modifier = Modifier.fillMaxWidth()) {
if (contact[0].image != null) {
Image(
painter = rememberImagePainter(data = contact[0].image),
contentDescription = "Image",
modifier = Modifier.fillMaxWidth(),
contentScale = ContentScale.Crop
)
} else {
Box(
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth()
.background(color = Color.Magenta),
contentAlignment = Alignment.Center,
) {
Text(
text = contact[0].first_name[0].toString(),
fontSize = 26.sp,
fontWeight = FontWeight.Bold
)
}
}
Box(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(),
contentAlignment = Alignment.BottomStart
) {
Text(
text = "${contact.first().first_name} ${contact.first().last_name}",
modifier = Modifier,
color = Color.White,
style = MaterialTheme.typography.h4,
fontWeight = FontWeight.Bold
)
}
}
}
Divider(
color = Color.LightGray,
thickness = 2.dp,
)
phoneCard(contact = contact.first(), contactViewModel)
emailCard(contact = contact.first(), contactViewModel)
}
}
#Composable
fun phoneCard(contact: Contact, contactViewModel: ContactViewModel) {
val phoneList = contactViewModel.getPhoneListByContactId(contact.id)
Row(modifier = Modifier.padding(10.dp)) {
Icon(imageVector = Icons.Default.Phone, contentDescription = "Phone Icon")
Text(
text = "Phone:",
modifier = Modifier.padding(start = 10.dp),
textAlign = TextAlign.Center,
style = MaterialTheme.typography.h6,
fontWeight = FontWeight.Bold
)
}
LazyColumn {
items(items = phoneList) {
Row(modifier = Modifier.padding(10.dp)) {
Text(text = it.type + ": ", fontWeight = FontWeight.Bold)
Text(text = it.number)
}
}
}
}
#Composable
fun emailCard(contact: Contact, contactViewModel: ContactViewModel) {
val emailList = contactViewModel.getEmailListByContactId(contact.id)
Row(modifier = Modifier.padding(10.dp)) {
Icon(imageVector = Icons.Default.Email, contentDescription = "Email Icon")
Text(
text = "Email:",
modifier = Modifier.padding(start = 10.dp),
textAlign = TextAlign.Center,
style = MaterialTheme.typography.h6,
fontWeight = FontWeight.Bold
)
}
LazyColumn {
items(items = emailList) {
Row(modifier = Modifier.padding(10.dp)) {
Text(text = it.type + ": ", fontWeight = FontWeight.Bold)
Text(text = it.address)
}
}
}
}
here is my emulator:
my description page
Specify a height in your LazyColumns for example:
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
) {

How can I put the bottom bar inside the surface in kotlin compose?

I want the bottom bar to be where I show it at the bottom, but it will overlap with the surface, so I want the bottom bar at the bottom and the bottom bar on the surface. I tried to put it in the box, but I couldn't do that and I don't want to create your own dictionary text corrupted, I want to adjust accordingly. I couldn't adapt this to my own code. Please help me how can I do this.
my screen
#Composable
fun CreateDicScreen() {
var text = remember { mutableStateOf("") }
Card()
Surface(color = Color.White, modifier = Modifier
.requiredHeight(600.dp)
.fillMaxWidth(),
shape = RoundedCornerShape(60.dp).copy(topStart = ZeroCornerSize, topEnd = ZeroCornerSize)) {
Column(modifier = Modifier
.padding(5.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Image(
painter = painterResource(id = R.drawable.resim ),
contentDescription = "image",
modifier = Modifier
.padding(5.dp)
.requiredHeight(300.dp)
.requiredWidth(300.dp)
)
Spacer(modifier = Modifier.padding(16.dp))
OutlinedTextField(
value = text.value,
onValueChange = { text.value = it },
modifier= Modifier
.fillMaxWidth()
.padding(5.dp)
,
textStyle = TextStyle(color = Color.Black),
label = { Text(text = "dictionary name") },
colors = TextFieldDefaults.outlinedTextFieldColors(
//focusedBorderColor = Color.Blue,
unfocusedBorderColor = Color.Blue
),
)
Spacer(modifier=Modifier.padding(5.dp))
Button(onClick = {},
modifier= Modifier
.padding(5.dp)
.fillMaxWidth(),
colors = ButtonDefaults.buttonColors(
backgroundColor = orangish,
contentColor = Color.White),
shape = shapes.medium,
contentPadding = PaddingValues(8.dp),
) {
Text(text = "Save")
}
}
}
}
#Composable
fun Card(){
Surface(color = purplish, modifier = Modifier.fillMaxSize()) {
Column(verticalArrangement = Arrangement.Bottom,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.offset(y = (-30).dp)
) {
Spacer(modifier = Modifier.padding(vertical = 8.dp))
Text(text = "create your own dictionary", color = Color.White)
}
}
}
#Composable
fun bottomBar(){
var bottomState = remember {
mutableStateOf("Home")
}
Scaffold(
bottomBar = {
BottomNavigation(
modifier = Modifier
.clip(shape = RoundedCornerShape(topStart = 30.dp, topEnd = 30.dp)),
backgroundColor = Color(0xFFFEDBD0),
contentColor = Color(0xFF442c2E)
) {
BottomNavigationItem(
selected = bottomState.equals("Home") ,
onClick = { bottomState.equals("Home")},
label = { Text(text = "Home")},
icon = { Icon(imageVector = Icons.Default.Home, contentDescription = null)}
)
BottomNavigationItem(
selected = bottomState.equals("Account") ,
onClick = { bottomState.equals("Account")},
label = { Text(text = "Account")},
icon = { Icon(imageVector = Icons.Default.AccountCircle, contentDescription = null)}
)
BottomNavigationItem(
selected = bottomState.equals("Search") ,
onClick = { bottomState.equals("Search")},
label = { Text(text = "Search")},
icon = { Icon(imageVector = Icons.Default.Search, contentDescription = null)}
)
BottomNavigationItem(
selected = bottomState.equals("Setting") ,
onClick = { bottomState.equals("Setting") },
label = { Text(text = "Setting")},
icon = { Icon(imageVector = Icons.Default.Settings, contentDescription = null)}
)
}
}
){
}
}
my screen right now
First, you can show bottomNavigation with Scaffold as you wrote in your code, but you don't need to use Scaffold if it's only purpose is to show bottomNavigation (inside your bottomBar() composable). You can use Box.
#Composable
fun bottomBar() {
val bottomState = remember {
mutableStateOf("Home")
}
Box {
BottomNavigation(
modifier = Modifier
.clip(shape = RoundedCornerShape(topStart = 30.dp, topEnd = 30.dp)),
backgroundColor = Color(0xFFFEDBD0),
contentColor = Color(0xFF442c2E)
) {
BottomNavigationItem(
selected = bottomState.equals("Home"),
onClick = { bottomState.equals("Home") },
label = { Text(text = "Home") },
icon = { Icon(imageVector = Icons.Default.Home, contentDescription = null) }
)
BottomNavigationItem(
selected = bottomState.equals("Account"),
onClick = { bottomState.equals("Account") },
label = { Text(text = "Account") },
icon = {
Icon(imageVector = Icons.Default.AccountCircle,
contentDescription = null)
}
)
BottomNavigationItem(
selected = bottomState.equals("Search"),
onClick = { bottomState.equals("Search") },
label = { Text(text = "Search") },
icon = { Icon(imageVector = Icons.Default.Search, contentDescription = null) }
)
BottomNavigationItem(
selected = bottomState.equals("Setting"),
onClick = { bottomState.equals("Setting") },
label = { Text(text = "Setting") },
icon = { Icon(imageVector = Icons.Default.Settings, contentDescription = null) }
)
}
}
}
To show your bottomBar() on screen, you have several ways to do that. You can use Box again:
#Composable
fun CreateDicScreen() {
var text = remember { mutableStateOf("") }
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.BottomCenter) {
Card()
bottomBar()
Box(modifier = Modifier.fillMaxHeight()) {
Surface(
color = Color.White,
modifier = Modifier
.requiredHeight(600.dp)
.fillMaxWidth(),
shape = RoundedCornerShape(60.dp).copy(topStart = ZeroCornerSize,
topEnd = ZeroCornerSize)
) {
...
}
}
}
}
With this approach we were forced to set contentAlignment to Bottom, and to wrap Surface with another Box layout and fill height of it.
Second way if you want bottomBar() to be in your Surface (inside composable "Card" (as you named it)), you can do that like this:
#Composable
fun CreateDicScreen() {
var text = remember { mutableStateOf("") }
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.BottomCenter) {
Card()
Box(modifier = Modifier.fillMaxHeight()) {
Surface(
color = Color.White,
modifier = Modifier
.requiredHeight(600.dp)
.fillMaxWidth(),
shape = RoundedCornerShape(60.dp).copy(topStart = CornerSize(0.dp),
topEnd = CornerSize(0.dp))
) {
...
}
}
}
}
#Composable
fun Card() {
Surface(color = Color.Magenta, modifier = Modifier.fillMaxSize()) {
Column(
verticalArrangement = Arrangement.Bottom,
horizontalAlignment = Alignment.CenterHorizontally,
) {
Spacer(modifier = Modifier.padding(vertical = 8.dp))
bottomBar()
}
}
}
and the bottomBar() stays as I mentioned above.
Extra:
I recommend you to use Scaffold for you design (if you don't have specific reason to put your bottomBar in Surface) because it has all features you need here. Here is your design only with Scaffold:
#Composable
fun CreateDicScreen() {
var text = remember { mutableStateOf("") }
Scaffold(
modifier = Modifier
.fillMaxSize(),
bottomBar = { bottomBar() }
) {
Surface(
color = Color.LightGray,
modifier = Modifier
.requiredHeight(600.dp)
.fillMaxWidth(),
shape = RoundedCornerShape(60.dp).copy(topStart = CornerSize(0.dp),
topEnd = CornerSize(0.dp))
) {
...
}
}
}
P.S. While trying to run your code on my Android I've received several times
java.lang.IllegalArgumentException: Corner size in Px can't be negative(topStart = 78.75, topEnd = -196350.0, bottomEnd = 0.0, bottomStart = 0.0)!
change your ZeroCornerSize for Surface to CornerSize(0.dp) to avoid this error.
Your Screen on phone

How send the value to child compose which is viewmodel value?

Here is my code.
DrawerCompose
#Composable
fun DrawerCompose(
modifier: Modifier = Modifier,
onDestinationClicked: (route: String) -> Unit
) {
val versionName = BuildConfig.VERSION_NAME
val empno by remember {
mutableStateOf("")
}
val password by remember {
mutableStateOf("")
}
Column(
modifier = Modifier
.background(MaterialTheme.colors.primarySurface)
.fillMaxSize()
) {
Box(
modifier = Modifier
.fillMaxWidth()
) {
Column(
modifier = Modifier
.padding(20.dp)
) {
Text(
text = "Title",
fontSize = 25.sp,
textAlign = TextAlign.Center,
fontWeight = FontWeight.Bold,
color = Color.White
)
Spacer(modifier = Modifier.height(16.dp))
Text(
text = "ID",
fontSize = 25.sp,
textAlign = TextAlign.Center,
fontWeight = FontWeight.Bold,
color = Color.White
)
OutlinedTextField(
value = empno,
onValueChange = {
},
modifier = Modifier
.fillMaxWidth(),
label = { Text(text = "ID") },
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
)
)
Text(
text = "Password",
fontSize = 25.sp,
textAlign = TextAlign.Center,
fontWeight = FontWeight.Bold,
color = Color.White
)
OutlinedTextField(
value = password,
onValueChange = {
},
modifier = Modifier
.fillMaxWidth(),
label = { Text(text = "Password") },
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(
onDone = {
}
)
)
Text(
text = "v $versionName",
fontSize = 25.sp,
textAlign = TextAlign.Center,
fontWeight = FontWeight.Bold,
color = Color.White
)
}
}
}
}
MenuListScreen
#OptIn(ExperimentalFoundationApi::class)
#Composable
fun HomeScreen(
navController: NavController,
onNavigateToMenuDetailScreen: (String) -> Unit,
viewModel: MenuListViewModel,
) {
val context = LocalContext.current
val menuList = viewModel.menuList.value
val scope = rememberCoroutineScope()
val scaffoldState = rememberScaffoldState(
rememberDrawerState(initialValue = DrawerValue.Closed)
)
val loading = viewModel.loading.value
val dialogQueue = viewModel.dialogQueue
Scaffold(
modifier = Modifier.fillMaxSize(),
topBar = {
TopAppBarCompose(
title = "Title",
navigationIcon = {
IconButton(onClick = {
scope.launch {
scaffoldState.drawerState.open()
}
}) {
Icon(imageVector = Icons.Filled.Menu, contentDescription = "")
}
}
)
},
scaffoldState = scaffoldState,
drawerContent = {
DrawerCompose(
onDestinationClicked = { route ->
scope.launch {
scaffoldState.drawerState.close()
}
}
)
},
drawerGesturesEnabled = true
) {
MenuList(
loading = loading,
menus = menuList,
onNavigateToSubmenuScreen = onNavigateToMenuDetailScreen
)
}
}
MenuListViewModel
#HiltViewModel
class MenuListViewModel #Inject constructor(
private val restoreMenus: RestoreMenus,
private val assetsManager: AssetsManager,
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
val id: MutableState<String> = mutableStateOf("")
val password: MutableState<String> = mutableStateOf("")
fun onChangeEmpNo(id: String) {
this.id.value = id
}
fun onChangePassword(password: String) {
this.password.value = password
}
}
If the value in the ID TextField in the drawer changes, the empno value in the viewModel changes, and if the value in the ID in the viewModel changes, the value in the ID TextField in the drawer changes.
I'd like to know how to communicate with Viewmodel and Child Compose.
Edit
I solved that pass the viewmodel variables to drawer, and viewmodel function
You have to pass callback function
#Composable
fun DrawerCompose(
modifier: Modifier = Modifier,
onDestinationClicked: (route: String) -> Unit,
onIdChange: (value: String) -> Unit,
onPasswordChange: (value: String) -> Unit,
) {
val versionName = BuildConfig.VERSION_NAME
val empno by remember {
mutableStateOf("")
}
val password by remember {
mutableStateOf("")
}
Column(
modifier = Modifier
.background(MaterialTheme.colors.primarySurface)
.fillMaxSize()
) {
Box(
modifier = Modifier
.fillMaxWidth()
) {
Column(
modifier = Modifier
.padding(20.dp)
) {
Text(
text = "Title",
fontSize = 25.sp,
textAlign = TextAlign.Center,
fontWeight = FontWeight.Bold,
color = Color.White
)
Spacer(modifier = Modifier.height(16.dp))
Text(
text = "ID",
fontSize = 25.sp,
textAlign = TextAlign.Center,
fontWeight = FontWeight.Bold,
color = Color.White
)
OutlinedTextField(
value = empno,
onValueChange = onIdChange,
modifier = Modifier
.fillMaxWidth(),
label = { Text(text = "ID") },
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
}
)
)
Text(
text = "Password",
fontSize = 25.sp,
textAlign = TextAlign.Center,
fontWeight = FontWeight.Bold,
color = Color.White
)
OutlinedTextField(
value = password,
onValueChange = onPasswordChange,
modifier = Modifier
.fillMaxWidth(),
label = { Text(text = "Password") },
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(
onDone = {
}
)
)
Text(
text = "v $versionName",
fontSize = 25.sp,
textAlign = TextAlign.Center,
fontWeight = FontWeight.Bold,
color = Color.White
)
}
}
}
}
After that pass those function from main screen
#OptIn(ExperimentalFoundationApi::class)
#Composable
fun HomeScreen(
navController: NavController,
onNavigateToMenuDetailScreen: (String) -> Unit,
viewModel: MenuListViewModel,
) {
val context = LocalContext.current
val menuList = viewModel.menuList.value
val scope = rememberCoroutineScope()
val scaffoldState = rememberScaffoldState(
rememberDrawerState(initialValue = DrawerValue.Closed)
)
val loading = viewModel.loading.value
val dialogQueue = viewModel.dialogQueue
Scaffold(
modifier = Modifier.fillMaxSize(),
topBar = {
TopAppBarCompose(
title = "Title",
navigationIcon = {
IconButton(onClick = {
scope.launch {
scaffoldState.drawerState.open()
}
}) {
Icon(imageVector = Icons.Filled.Menu, contentDescription = "")
}
}
)
},
scaffoldState = scaffoldState,
drawerContent = {
DrawerCompose(
onDestinationClicked = { route ->
scope.launch {
scaffoldState.drawerState.close()
}
},
viewModel.onChangeEmpNo,
viewModel.onChangePassword
)
},
drawerGesturesEnabled = true
) {
MenuList(
loading = loading,
menus = menuList,
onNavigateToSubmenuScreen = onNavigateToMenuDetailScreen
)
}
}

Navigation in Jetpack Compose

I am working on this shopping app which uses radio buttons. The customer should be able to select a radio button and go it by clicking the 'select button'.
Can anyone help me get get started.
the code is below.
I hope this makes sense to everyone. I have made a page for each of the radio buttons. pages are name the same as the buttons.
#Composable
fun MyRadioGroup() {
val navController = rememberNavController()
val radioOptions = listOf(
"Dollar Store", "Fred Myers",
"Wall Mart", "SafeWay", "Sherm's", "CostCo", "Other"
)
val (selectedOption, onOptionSelected) = remember {
mutableStateOf(radioOptions[1])
}
Scaffold() {
TopAppBar(
title = { Text(stringResource(id = R.string.app_name)) },
)
}
Column(
modifier = Modifier
.padding(start = 16.dp, top = 160.dp)
) {
Text(
text = "Select Store from List Below")
Divider()
Text(
text = "Then push the 'Select'")
}
Column(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
radioOptions.forEach { text ->
Row(
Modifier
.fillMaxWidth()
.padding(top = 8.dp)
.selectable(
selected = (text == selectedOption),
onClick = { onOptionSelected(text) }
)
.padding(horizontal = 16.dp)
) {
RadioButton(
selected = (text == selectedOption),
modifier = Modifier
.padding(start = 16.dp, top = 12.dp),
onClick = {
onOptionSelected(text)
}
)
Text(
text = text,
modifier = Modifier.padding(start = 16.dp, top = 16.dp)
)
}
}
}
Column(modifier = Modifier
.padding(start = 24.dp, top = 640.dp)
) {
Button(onClick = {
TODO()
}) {
Text(text = "Select")
}
}
}
The 'select' button is near the bottom of the code.
First create a sealed class Screen to link radio buttons text to composable as recommended by Google like this:
sealed class Screen(val route: String, val label: String){
object MyRadioGroup: Screen(route = "myRadioGroup", label = "APP NAME")
object DollarStore: Screen(route = "Dollar Store", label = "Dollar Store")
object FreedMyers: Screen(route = "Fred Myers", label = "FreedMyers")}
then modify NavHost or AnimatedNavHost(if you are using accompanist's Navigatio Animatation library as:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val navController = rememberNavController()
Surface(color = MaterialTheme.colors.background) {
NavHost(navController = navController, startDestination = Screen.MyRadioGroup.route){
composable(Screen.MyRadioGroup.route){
MyRadioGroup(navController = navController)
}
composable(Screen.DollarStore.route){
//Call here the associated composable function
DollarStore()
}
composable(Screen.FreedMyers.route){
//Call here the associated composable function
FreedMyers()
}
}
}
}
}}
Finally add some code to MyRadioGroup Composable
fun MyRadioGroup(navController: NavController) {
val radioOptions = listOf(
"Dollar Store", "Fred Myers",
"Wall Mart", "SafeWay", "Sherm's", "CostCo", "Other"
)
val (selectedOption, onOptionSelected) = remember {
mutableStateOf(radioOptions[1])
}
Scaffold(
topBar = {
TopAppBar(
title = { Text(stringResource(id = R.string.app_name)) },
)
}
) {
Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
Column(
modifier = Modifier.padding(start = 16.dp, top = 16.dp)
) {
Text(text = "Select Store from List Below")
Divider()
Text(text = "Then push the 'Select'")
}
Column(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
radioOptions.forEach { text ->
Row(
Modifier
.fillMaxWidth()
.padding(top = 8.dp)
.selectable(
selected = (text == selectedOption),
onClick = { onOptionSelected(text) }
)
.padding(horizontal = 16.dp)
) {
RadioButton(
selected = (text == selectedOption),
modifier = Modifier
.padding(start = 16.dp, top = 12.dp),
onClick = { onOptionSelected(text) }
)
Text(
text = text,
modifier = Modifier.padding(start = 16.dp, top = 16.dp)
)
}
}
}
Column(
modifier = Modifier
.padding(start = 24.dp, top = 24.dp)
) {
Button(
onClick = {
navController.navigate(selectedOption) //navigate to selected route
}
) {
Text(text = "Select")
}
}
}
}}