2

I am trying to make a custom TopBar for my application and I want to have a DropdownMenu displayed in the top right corner of the screen. I have a Box that contains a Row (with some text and icons) and a DropdownMenu which is initially not displayed. When I click on an icon, the DropdownMenu is displayed, but outside the Box, so not where I intended. The code:

@Composable
private fun TopBar {
    var expanded by remember { mutableStateOf(false) }
    Box(
        modifier = Modifier
            .border(1.dp, Color.Black)
    ) {
        Row(
            verticalAlignment = Alignment.CenterVertically
        ) {
            Text(
                text = "Ride history",
                maxLines = 1,
                fontSize = 25.sp
            )

            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.End
            ) {
                IconButton(
                    onClick = {}) {
                    Icon(imageVector = Icons.Filled.Search, contentDescription = null)
                }
                IconButton(
                    onClick = { expanded = !expanded }) {
                    Icon(imageVector = Icons.Filled.Sort, contentDescription = null)
                }
                IconButton(
                    onClick = { findNavController().navigate(RideFragmentDirections.actionRideFragmentToSettingsFragment())}) {
                    Icon(imageVector = Icons.Filled.Settings, contentDescription = null)
                }
            }
        }
        DropdownMenu(
            modifier = Modifier.align(Alignment.TopEnd),
            expanded = expanded,
            onDismissRequest = { expanded = false }
        ) {
            DropdownMenuItem(onClick = {}) {
                Text(text = "BlaBla")
            }
            DropdownMenuItem(onClick = {}) {
                Text(text = "BlaBla")
            }
        }
    }
}

What I obtain:

enter image description here

(I put a border around the Box to see its bounds)

After I press the Sort button, the DropdownMenu appears, but it is placed outside the Box. I want it to be placed in the top right corner, over everything. What am I missing?

Update

@Composable
private fun TopBar() {
    var expanded by remember { mutableStateOf(false) }
    Box(
        modifier = Modifier
            .border(1.dp, Color.Black)
    ) {
        Row(
            verticalAlignment = Alignment.CenterVertically
        ) {
            Text(
                text = "Ride history",
                maxLines = 1,
                fontSize = 25.sp
            )

            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.End
            ) {
                IconButton(
                    onClick = {}
                ) {
                    Icon(imageVector = Icons.Filled.Search, contentDescription = null)
                }
                IconButton(
                    onClick = { expanded = !expanded }
                ) {
                    Icon(imageVector = Icons.Filled.Sort, contentDescription = null)
                }
                IconButton(
                    onClick = {}
                ) {
                    Icon(imageVector = Icons.Filled.Settings, contentDescription = null)
                }
            }
        }
        Box(
            modifier = Modifier.fillMaxHeight().align(Alignment.TopEnd),
            contentAlignment = Alignment.TopEnd
        ) {
            DropdownMenu(
                expanded = expanded,
                onDismissRequest = { expanded = false }
            ) {
                DropdownMenuItem(onClick = {}) {
                    Text(text = "BlaBla")
                }
                DropdownMenuItem(onClick = {}) {
                    Text(text = "BlaBla")
                }
            }
        }
    }
}

This yields:

enter image description here

daniyelp
  • 915
  • 1
  • 11
  • 26
  • Try placing DropdownMenu inside another Box with contentAlignment = Alignment.TopStart – LaC Sep 27 '21 at 07:06
  • Does this answer your question? [DropDownMenu in Compose no align at end of the row](https://stackoverflow.com/questions/68728375/dropdownmenu-in-compose-no-align-at-end-of-the-row) – Phil Dukhov Sep 27 '21 at 08:36
  • @PhilipDukhov Sort of! I wrapped `DropdownMenu` with `modifier = Modifier.align(Alignment.TopEnd), contentAlignment = Alignment.TopEnd )` but it is not enough. My dropdownMenu is displayed at the end of the row, which is good, but not right at the top of the row but the center of it (the icons are cut in half). I think that might be caused by the `Alignment.CenterVertically` of the `Row`, but I need this modifier. – daniyelp Sep 27 '21 at 09:34
  • @LaC Thanks. Sadly not enough ); – daniyelp Sep 27 '21 at 09:35
  • @daniyelp could you update your code and image with the result you've got? – Phil Dukhov Sep 27 '21 at 09:37
  • @PhilipDukhov I just did. – daniyelp Sep 27 '21 at 09:51
  • @daniyelp It will not be placed on top of the row. `DropdownMenu` is part of Material items, and according to [Material guidelines](https://material.io/components/menus#dropdown-menu) should be placed below the element. Right now it's placed in the middle, because you didn't exactly follow my answer: you need to place it in a `Box` with the button that opens it, in this case it will open under that button. – Phil Dukhov Sep 27 '21 at 10:15
  • @PhilipDukhov I tried it as you said. Surprsingly the DropdownMenu still starts from the center. But I think I'll abandon this and stick to the Material guidlines. Thanks for pointing that out to me. – daniyelp Sep 27 '21 at 10:37

1 Answers1

3

According to Material guidelines the dropdown menu should be placed below the element.

To get this layout in Compose with DropdownMenu, you need to put it in a Box with the calling button, like this:

Box {
    IconButton(
        onClick = { expanded = !expanded }
    ) {
        Icon(imageVector = Icons.Filled.Sort, contentDescription = null)
    }
    DropdownMenu(
        expanded = expanded,
        onDismissRequest = { expanded = false }
    ) {
        DropdownMenuItem(onClick = {}) {
            Text(text = "BlaBla")
        }
        DropdownMenuItem(onClick = {}) {
            Text(text = "BlaBla")
        }
    }
}

Output where Sort is the calling button:

Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
  • Look what I have bumped into right now xd: https://www.material.io/components/menus/android#dropdown-menus. `OverFlow Menus`. So this means it's up to me what menu style I choose? – daniyelp Sep 27 '21 at 11:12
  • 1
    @daniyelp yes, but at the moment Compose does not implement anything like `OverflowMenu`. You can try to implement it yourself. – Phil Dukhov Sep 27 '21 at 11:28