Hey there. I'm having trouble with interactive pre...
# compose
m
Hey there. I'm having trouble with interactive preview.
I have a button that shows some composable content on click. It works fine in the app but the preview does not show the content on click. I'm using a remember function to keep track of if content is displayed or not, is there any know issues with this and a preview?
c
Do you have a code snippet? And what version of Compose? We have a known issue around animate*AsState not working properly in Interactive Preview, but maybe this is related.
m
Compose Version
1.4.3
Button Composable:
Copy code
@Composable
fun RectangleIconButton(
    @DrawableRes iconResId: Int,
    modifier: Modifier = Modifier,
    isEnabled: Boolean = true,
    onClick: () -> Unit = {},
    content: (@Composable () -> Unit) = {}
) {
    CompositionLocalProvider(LocalRippleTheme provides NoRippleTheme) {
        val interactionSource = remember { MutableInteractionSource() }
        val isPressed by interactionSource.collectIsPressedAsState()
        var showContent by remember { mutableStateOf(false) }
        val borderColor =
            if (isPressed && isEnabled) Color.TenPercentBlack else Color.FivePercentBlack

        Button(
            onClick = {
                onClick()
                showContent = !showContent
            },
            modifier =
                modifier.border(
                    width = 2.dp, color = borderColor, shape = RoundedCornerShape(16.dp)),
            shape = RoundedCornerShape(size = 16.dp),
            interactionSource = interactionSource,
            colors =
                ButtonDefaults.buttonColors(
                    containerColor = Color.White, disabledContainerColor = Color.White),
            contentPadding = PaddingValues(horizontal = 24.dp, vertical = 18.dp),
            enabled = isEnabled) {
                Icon(
                    painter = painterResource(id = iconResId),
                    contentDescription = null,
                    tint = if (isEnabled) Color.Black else Color.FivePercentBlack,
                    modifier = Modifier.size(24.dp))
            }
        if (showContent) content()
    }
}
The
content
I would like to render in the preview:
Copy code
@Composable
fun InternalDropDownMenu(items: List<InternalDropDownMenuItem>) {

    var expanded by remember { mutableStateOf(true) }

    MaterialTheme(shapes = MaterialTheme.shapes.copy(extraSmall = RoundedCornerShape(24.dp))) {
        DropdownMenu(
            expanded = expanded,
            onDismissRequest = { expanded = false },
            modifier = Modifier.width(240.dp).height(188.dp).background(color = Color.White)) {
                for (i in items) {
                    DropdownMenuItem(
                        text = {
                            Text(
                                i.title,
                                style = TextStyle.Body)
                        },
                        onClick = i.onClick,
                        modifier = Modifier.padding(top = 8.dp, bottom = 8.dp, start = 8.dp))
                }
            }
    }
}
The preview:
Copy code
@Preview
@Composable
internal fun PreviewButtonDropDownMenu() {
    RectangleIconButton(
        iconResId = R.drawable.more,
        content = {
            InternalDropDownMenu(
                listOf(
                    InternalDropDownMenuItem("Test 1"),
                    InternalDropDownMenuItem("Test 2"),
                    InternalDropDownMenuItem("Test 3")))
        })
}
c
I don’t have the best technical explanation, but what I can see is that your DropdownMenu is not anchored to a specific container and Preview will by default size the frame based on the content size. My suggestion is you should have at least a Box to keep your Button and DropdownMenu in the same container, like the example here: https://developer.android.com/reference/kotlin/androidx/compose/material/package-summary#DropdownMenu(kotlin.Boolean,[…]Properties,kotlin.Function1)
If you look at the docs, it says “A
DropdownMenu
behaves similarly to a
Popup
, and will use the position of the parent layout to position itself on screen. Commonly a
DropdownMenu
will be placed in a Box with a sibling that will be used as the ‘anchor’.” In your case, you don’t have the
Box
to anchor to. So in your Preview it has no parent to position itself relative to. When I added a Surface/Column with fillMaxSize(), I could see the dropdown show up towards the bottom.