Reputation: 9380
How to create a dropdown menu items on a button click. In Jetpack compose?
Like here but for buttons :
DropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
toggle = iconButton,
dropdownOffset = Position(24.dp, 0.dp),
toggleModifier = modifier
) {
options.forEach {
DropdownMenuItem(onClick = {}) {
Text(it)
}
}
}
Upvotes: 1
Views: 5701
Reputation: 301
you can create a dropdown list in compose by using this
list : list you want to show
label : label is the hint to show in the textview
default : to set default value in textview
validateInput = you can validate the input by changing the validateInput state to true on the button clicked and handle it accordingly
fun dropdownList(
list: List<String>,
label: String,
defaultValue: String = "",
validateInput: Boolean
): String {
var expanded by remember { mutableStateOf(false) }
var selectedText by remember { mutableStateOf(defaultValue) }
var textFieldSize by remember { mutableStateOf(Size.Zero) }
var isError by remember { mutableStateOf(false) }
if (validateInput && selectedText.isEmpty())
isError = true
val icon = if (expanded)
Icons.Filled.ArrowDropUp
else
Icons.Filled.ArrowDropDown
Column(modifier = Modifier.padding(bottom = 2.dp, top = 2.dp)) {
OutlinedTextField(
value = selectedText,
onValueChange = {
selectedText = it
},
modifier = Modifier
.fillMaxWidth()
.onGloballyPositioned { coordinates ->
textFieldSize = coordinates.size.toSize()
},
label = { Text(label) },
trailingIcon = {
Icon(icon, "contentDescription",
Modifier.clickable { expanded = !expanded })
},
isError = isError
)
DropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
modifier = Modifier
.width(with(LocalDensity.current) { textFieldSize.width.toDp() })
) {
list.forEach { label ->
DropdownMenuItem(onClick = {
selectedText = label
expanded = false
}) {
Text(text = label)
}
}
}
if (isError) {
Text(
text = "$label can't be empty",
color = Color.Red,
textAlign = TextAlign.End,
modifier = Modifier.fillMaxWidth()
)
}
}
return selectedText
}
Github gist link DropdownList.kt
Upvotes: 0
Reputation: 1208
The previous answer is correct, but the key part is missing. Both, DropdownMenu and the button that opens it suppose to be wrapped in Box. Only this way the opening button will be used as an anchor for the menu. This is my version:
@Composable
fun DropdownMenu(
colorSelected: Color = scColors.primary,
colorBackground: Color = scColors.onSurface,
expanded: Boolean,
selectedIndex: Int,
items: List<String>,
onSelect: (Int) -> Unit,
onDismissRequest: () -> Unit,
content: @Composable () -> Unit
) {
Box {
content()
DropdownMenu(
expanded = expanded,
onDismissRequest = onDismissRequest,
modifier = Modifier
.height(300.dp)
.fillMaxWidth()
.background(
color = colorBackground,
shape = RoundedCornerShape(16.dp)
)
) {
items.forEachIndexed { index, s ->
if (selectedIndex == index) {
DropdownMenuItem(
modifier = Modifier
.fillMaxWidth()
.background(
color = colorSelected,
shape = RoundedCornerShape(16.dp)
),
onClick = { onSelect(index) }
) {
Text(
text = s,
color = Color.Black,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
}
} else {
DropdownMenuItem(
modifier = Modifier.fillMaxWidth(),
onClick = { onSelect(index) }
) {
Text(
text = s,
color = Color.DarkGray,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
}
}
}
}
}
}
And, then a DropdownMenu accepts the opening anchor button as a content:
val items = listOf(
"English",
"Russian",
"Spanish",
"French",
"German",
"Hebrew"
)
@Preview
@Composable
fun TestDropdownMenu() {
var expanded by remember { mutableStateOf(false) }
var selectedIndex by remember { mutableStateOf(0) }
val buttonTitle = items[selectedIndex]
DropdownMenu(
colorSelected = scColors.onSurface,
colorBackground = scColors.primary,
expanded = expanded,
selectedIndex = selectedIndex,
items = items,
onSelect = { index ->
selectedIndex = index
expanded = false
},
onDismissRequest = {
expanded = false
}) {
Button(
onClick = {
expanded = true
}
) {
Text(
text = buttonTitle,
color = Color.Black,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
}
}
}
Upvotes: 4
Reputation: 363935
You can use something like:
var expanded by remember { mutableStateOf(false) }
Button(onClick = { expanded = true }){
Text ("...")
}
DropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
//....
) {
items.forEachIndexed { index, s ->
//....
}
}
Upvotes: 1