Hi, I need help. How to make drop down menu like on photos? Is there any easy way?
You can use the standard ExposedDropdownMenuBox provided by M3.
Something like:
val options = listOf("Option 1", "Option 2", "Option 3", "Option 4", "Option 5")
var expanded by remember { mutableStateOf(false) }
var selectedOptionText by remember { mutableStateOf(options[0]) }
val shape = if (expanded) RoundedCornerShape(8.dp).copy(bottomEnd = CornerSize(0.dp), bottomStart = CornerSize(0.dp))
else RoundedCornerShape(8.dp)
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = { expanded = !expanded },
) {
TextField(
modifier = Modifier.menuAnchor(),
textStyle = TextStyle.Default.copy(
fontSize = 14.sp,
fontWeight= FontWeight.Light),
readOnly = true,
value = selectedOptionText,
onValueChange = {},
label = { Text("Unit of length", fontWeight = FontWeight.Bold, ) },
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
shape = shape,
colors = ExposedDropdownMenuDefaults.textFieldColors(
focusedIndicatorColor = Transparent,
unfocusedIndicatorColor = Transparent
)
)
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
) {
options.forEach { selectionOption ->
DropdownMenuItem(
text = { Text(selectionOption) },
onClick = {
selectedOptionText = selectionOption
expanded = false
},
contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
)
}
}
}
Related
I am doing some things with Compose and i encountered this problem
I cant understand WHY my textfield width is to the end of the parent. I want to wrap the content dependening on the input lenght. I painted the background red on purpouse.
I cant hardcode a padding because if the lenght of the field is too much the text starts to go out sight
What i am doing wrong?
Row(Modifier.wrapContentSize()) {
ConstraintLayout(
Modifier
.wrapContentSize()
) {
val (text1, text2) = createRefs()
Text(
modifier = modifier
.wrapContentWidth()
.constrainAs(text1) {
end.linkTo(text2.start)
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
},
text = "$",
color = Color.White,
fontSize = sp_50,
fontFamily = FontFamily(
Font(R.font.mulish_bold)
),
textAlign = TextAlign.Center
)
TextField(
modifier = modifier
.wrapContentWidth()
.constrainAs(text2) {
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
start.linkTo(text1.end)
}.background(Color.Red),
visualTransformation = {
show = it.isNotEmpty()
val value =
if (it.isEmpty())
NUM_0
else it.text
val amountFormat: String = notFormatAmount(value).toStringThousandAmount()
TransformedText(
AnnotatedString(amountFormat.take(amountFormat.length)),
OffsetMapping.Identity
)
},
value = text,
onValueChange = {
text = it
if (onTextChange != null) {
onTextChange(
it.ifEmpty { NUM_0 }
)
}
},
colors = TextFieldDefaults.textFieldColors(
textColor = Color.White,
disabledTextColor = Color.Transparent,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent,
cursorColor = Color.Transparent
),
textStyle = TextStyle(
color = Color.White,
fontFamily = FontFamily(
Font(R.font.mulish_bold)
),
textAlign = TextAlign.Justify,
fontSize = sp_50
),
singleLine = true,
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.NumberPassword)
)
}
}
Modified code:
Row(Modifier.wrapContentSize()) {
ConstraintLayout(
Modifier
.wrapContentSize()
) {
val (text1, text2) = createRefs()
Text(
modifier = modifier
.wrapContentWidth()
.constrainAs(text1) {
end.linkTo(text2.start)
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
},
text = "$",
color = Color.White,
fontSize = sp_50,
fontFamily = FontFamily(
Font(R.font.mulish_bold)
),
textAlign = TextAlign.Center
)
TextField(
modifier = modifier
.wrapContentWidth()
.constrainAs(text2) {
top.linkTo(parent.top)
bottom.linkTo(parent.bottom)
start.linkTo(text1.end)
width = Dimension.fillToConstraints
}.background(Color.Red),
visualTransformation = {
show = it.isNotEmpty()
val value =
if (it.isEmpty())
NUM_0
else it.text
val amountFormat: String = notFormatAmount(value).toStringThousandAmount()
TransformedText(
AnnotatedString(amountFormat.take(amountFormat.length)),
OffsetMapping.Identity
)
},
value = text,
onValueChange = {
text = it
if (onTextChange != null) {
onTextChange(
it.ifEmpty { NUM_0 }
)
}
},
colors = TextFieldDefaults.textFieldColors(
textColor = Color.White,
disabledTextColor = Color.Transparent,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent,
cursorColor = Color.Transparent
),
textStyle = TextStyle(
color = Color.White,
fontFamily = FontFamily(
Font(R.font.mulish_bold)
),
textAlign = TextAlign.Justify,
fontSize = sp_50
),
singleLine = true,
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.NumberPassword)
)
}
}
I have created a search view that takes input. If the input string is greater than or equal to 3 then a drop down is shown with some suggestion. That suggestion list comes from the server, but currently it shows for length 3, but I can't type more in textfield after 3 chars - the keyboard hides if try to write more.
Here is my code snippet.
val searchitems by viewmodel.stateFlowMessage.collectAsState()
var showdropdown by remember {
mutableStateOf(false)
}
Box(
Modifier
.fillMaxWidth()
.height(56.dp)
.background(Color.White), contentAlignment = Alignment.Center
) {
Column() {
TextField(
value = state.value,
onValueChange = {
state.value = it
if (state.value.text.length >= 3) {
searchquery()showdropdown = true
}
},
singleLine = true,
textStyle = TextStyle(
fontWeight = FontWeight(400),
color = Color.Black,
fontSize = 14.sp,
),
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth(1f),
placeholder = {
Text(
text = label,
modifier = Modifier
.wrapContentSize()
.padding(start = 15.dp),
style = TextStyle(
fontSize = 14.sp, color = colorResource(id = R.color.grey))
)
},
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Search,
autoCorrect = true,
),
leadingIcon = {
Image(
imageVector = Icons.Default.Search,
contentDescription = "",
modifier = Modifier
.size(24.dp)
.padding(start = 4.dp),
colorFilter = ColorFilter.tint(color = colorResource(id = R.color.grey))
)
},
colors = TextFieldDefaults.textFieldColors(
cursorColor = colorResource(id = R.color.grey),
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent,
backgroundColor = colorResource(id = R.color.col2)
)
)
}
DropdownMenu(expanded = showdropdown,
onDismissRequest = { showdropdown = false }, properties = PopupProperties(focusable = false)) {
Log.d("checks", "${searchitems.size}")
for (it in searchitems) {
DropdownMenuItem(onClick = {
selectitem(it)
state.value = TextFieldValue(it)
showdropdown = false
}
) {
Text(text = it,
style = TextStyle(fontSize = 14.sp,
color = Color.Black,
fontWeight = FontWeight(400)))
}
}
}
}
When i try to enter some inputs to text field, it draws underline, how to remove this underline without change any color of outlinedtextfield.
OutlinedTextField(modifier = Modifier
.fillMaxWidth()
.padding(16.dp),value = password,
onValueChange = {
password = it},
leadingIcon = { Icon(painter = painterResource(id = R.drawable.ic_baseline_vpn_key_24), contentDescription = "icon-content")},
trailingIcon = { IconButton(onClick = { passwordVisibility = !passwordVisibility }) {
Icon(painter = icon, contentDescription = "show-password")
}},
placeholder = { Text(text = "Password",
color = Color.LightGray)},
label = { BasicText(text = "Password")},
visualTransformation = if(passwordVisibility) VisualTransformation.None else PasswordVisualTransformation()
)
You should specify the keyboardType as Password to get rid of the text underline. You can do that by using KeyboardOptions:
OutlinedTextField(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
value = password,
onValueChange = { password = it },
leadingIcon = {
Icon(
painter = painterResource(id = R.drawable.ic_baseline_vpn_key_24),
contentDescription = "icon-content"
)
},
trailingIcon = {
IconButton(onClick = { passwordVisibility = !passwordVisibility }) {
Icon(painter = icon, contentDescription = "show-password")
}
},
placeholder = {
Text(
text = "Password",
color = Color.LightGray
)
},
label = { BasicText(text = "Password") },
visualTransformation = if (passwordVisibility) VisualTransformation.None else PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Password // HERE
),
)
This is the crucial change:
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Password
)
The underline text is not related to color of OutlinedTextField.
It is related to the keyboardType applied. The default value is KeyboardType.Text.
Just add in your in OutlinedTextField:
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password)
I want to set the "Account" text to the center of TopAppBar and add an icon to the right of TopAppBar, how can I do it?
Scaffold(
scaffoldState = scaffoldState,
topBar = {
TopAppBar(
title = {
Text(
text = stringResource(R.string.account),
style = AppFont.PoppinsTypography.subtitle1
)
},
navigationIcon = {
Icon(
painter = painterResource(id = R.drawable.ic_left),
contentDescription = "back", tint = AppColor.brandColor.BLUE_DE_FRANCE
)
}, actions = {
viewModel.navigateUp()
}, backgroundColor = AppColor.neutralColor.DOCTOR
)
},
)
To align the title text to the center of TopAppbar,
Update
Using Material 3
CenterAlignedTopAppBar(
title = {
Text(
text = stringResource(R.string.account),
style = AppFont.PoppinsTypography.subtitle1
)
},
)
And actions attribute should have the compoosables to add at the end. Use that to add an icon to the right of TopAppBar.
Example,
actions = {
IconButton(onClick = { /*TODO*/ }) {
Icon(
imageVector = Icons.Rounded.ShoppingCart,
contentDescription = "cart",
)
}
},
The old answer, using Material 2
Change title to this,
title = {
Text(
text = stringResource(R.string.account),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth(),
style = AppFont.PoppinsTypography.subtitle1
)
},
You could just implement a custom layout
#Composable
fun TopBar() {
Scaffold(
topBar = {
Layout(
modifier = Modifier.fillMaxHeight(0.1f), //Fills one-tenth of the screen
content = {
Text("Account")
Icon(
imageVector = Icons.Default.ArrowBack,
contentDescription = "back",
tint = Color.Blue,
)
}
) { measurables, constraints ->
val title = measurables[0].measure(constraints)
val navigationIcon = measurables[1].measure(constraints)
layout(constraints.maxWidth, constraints.maxHeight) {
title.place(
(constraints.maxWidth - title.width) / 2, //Midway
constraints.maxHeight / 2 // Usually Texts acquire maxHeight so we did not need t subtract
)
navigationIcon.place(
(constraints.maxWidth - 1.5 * navigationIcon.width).roundToInt(), //1.5 to add a bit of extra padding from the edge
(constraints.maxHeight - navigationIcon.height) / 2
)
}
}
},
) {
}
}
How to properly center an icon in ListItem?
Column {
ListItem(
icon = {
Icon(
imageVector = Icons.Outlined.Delete,
contentDescription = null
)
},
secondaryText = { Text("secondaryText") },
text = { Text("text") }
)
Divider()
}
gives this result
ListItem implementation uses explicit Box(contentAlignment = Alignment.TopStart) to place the icon. Mmm...why?
I can, of course, use paddings or create a custom ListItem, but there must be a standard solution.
According to M2 specs, you can add the Modifier.size(40.dp) to the Icon
Something like:
ListItem(
text = { Text("Two line list item with 40x40 icon") },
secondaryText = { Text("Secondary text") },
icon = {
Icon(
Icons.Filled.Favorite,
contentDescription = null,
modifier = Modifier.size(40.dp)
)
}
)
The ListItem follows the material guidelines:
With M3 it is not needed since the leadingContent has a default contentAlignment = Alignment.Center:
Column {
ListItem(
leadingContent = {
Icon(
imageVector = Icons.Outlined.Delete,
contentDescription = null
)
},
supportingText = { Text("Supporting Text") },
headlineText = { Text("Headline Text") }
)
Divider()
}
Specs: