21

I have a row with a text align at the start and a image align at the end. When I press the image I'm showing a DropdownMenu, but this appear in the start of the row and I want that appear at the end of the row.

I'm trying to use Alignment.centerEnd in Modifier component but is not working.

How can I do that the popup appear at the end of the row?

@Composable
fun DropdownDemo(currentItem: CartListItems) {
    var expanded by remember { mutableStateOf(false) }
    Box(modifier = Modifier
        .fillMaxWidth()) {
        Text(modifier = Modifier.align(Alignment.TopStart),
            text = currentItem.type,
            color = colorResource(id = R.color.app_grey_dark),
            fontSize = 12.sp)
        Image(painter = painterResource(R.drawable.three_dots),
            contentDescription = "more options button",
            Modifier
                .padding(top = 5.dp, bottom = 5.dp, start = 5.dp)
                .align(Alignment.CenterEnd)
                .width(24.dp)
                .height(6.75.dp)
                .clickable(indication = null,
                    interactionSource = remember { MutableInteractionSource() },
                    onClick = {
                        expanded = true
                    }))
        DropdownMenu(
            expanded = expanded,
            onDismissRequest = { expanded = false },
            modifier = Modifier
                .background(
                    Color.LightGray
                ).align(Alignment.CenterEnd),
        ) {
            DropdownMenuItem(onClick = { expanded = false }) {
                Text("Delete")
            }
            DropdownMenuItem(onClick = { expanded = false }) {
                Text("Save")
            }
        }
    }
}
Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
S.P.
  • 2,274
  • 4
  • 26
  • 57

3 Answers3

48

As documentation says:

A DropdownMenu behaves similarly to a Popup, and will use the position of the parent layout to position itself on screen.

You need to put DropdownMenu together with the caller view in a Box. In this case DropdownMenu will appear under the caller view.

var expanded by remember { mutableStateOf(false) }
Column {
    Text("Some text")
    Box {
        Image(
            painter = painterResource(R.drawable.test),
            contentDescription = "more options button",
            modifier = Modifier
                .clickable {
                    expanded = true
                }
        )
        DropdownMenu(
            expanded = expanded,
            onDismissRequest = { expanded = false },
        ) {
            DropdownMenuItem(onClick = { expanded = false }) {
                Text("Delete")
            }
            DropdownMenuItem(onClick = { expanded = false }) {
                Text("Save")
            }
        }
    }
}
Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
  • 3
    This code snippet will always show the dropdown menu in the left side. Is there any way to get it to show in the center? – kc_dev Feb 17 '22 at 18:19
  • 1
    @kc_dev it actually automatically detects the direction, if there is no space available to display on the right side, it will show it on the left side. I'm not sure if the material guidelines thinks displaying centered is a good idea, if you find such information - you can [open](https://issuetracker.google.com/issues/new?component=612128) a feature request. So far, the only thing you can adjust is the `offset` - you need to measure the width of the element as shown [here](https://stackoverflow.com/a/71162398/3585796) and add half that value to the `offset` parameter. – Phil Dukhov Feb 18 '22 at 04:41
  • 2
    Note that the menu will always be placed in the top-left corner of the screen for the **Live Preview** inside Android Studio. However the placement is correct on the emulator or a physical device. – nitro_nitrat Sep 26 '22 at 20:49
2

Use the offset parameter of the DropdownMenu().

DropdownMenu(
    offset = DpOffset(x = (-66).dp, y = (-10).dp)
)

Change the x and y values. They accept both positive and negative values.

SemicolonSpace
  • 1,007
  • 11
  • 20
0

When I press the image I'm showing a DropdownMenu, but this appear in the start of the row and I want that appear at the end of the row.

This is simple to achieve. Use contentAlignment = Alignment.TopStart on the parent Box of the DropdownMenu.

But it's also possible to place the DropDownMenu on the touch position by intercepting the touch events using Modifier.pointerInteropFilter().

Column(Modifier.padding(12.dp)) {
  var offset = Offset.Zero
  var dropDownExpanded by remember { mutableStateOf(false) }

  Card(
      Modifier.fillMaxWidth()
          .shadow(1.dp, CardDefaults.shape)
          .pointerInteropFilter {
            offset = Offset(it.x, it.y)
            false
          }
          .combinedClickable(onClick = {}, onLongClick = { dropDownExpanded = true })) {
        Box(contentAlignment = Alignment.TopStart) {
          Text(
              "Long press me",
              Modifier.fillMaxWidth().padding(vertical = 50.dp),
              textAlign = TextAlign.Center)
          Box {
            DropdownMenu(
                expanded = dropDownExpanded,
                offset = DpOffset(pxToDp(offset.x), pxToDp(offset.y)),
                onDismissRequest = { dropDownExpanded = false }) {
                  DropdownMenuItem(
                      text = { Text("Dismiss me") }, onClick = { dropDownExpanded = false })
                }
          }
        }
      }
}

Result:

Irfan Latif
  • 498
  • 2
  • 9
  • 24