kotlin Jetpack Compose中的DropDownMenu帧下降和滞后

mum43rcc  于 2023-03-30  发布在  Kotlin
关注(0)|答案(1)|浏览(161)

所以我现在有点为难。

开始

我有一个国家列表,我想让用户通过显示一个下拉菜单来选择其中的任何一个,早些时候没有喷气背包组成的方式,我在View上有一个扩展说View.setupDropDown,这反过来又加载了一个ListPopupWindow并将其锚定到当前视图,并显示所有项目,工作正常,没有jank或任何帧下降。
喜欢

val dropDown = ListPopupWindow(context)
    dropDown.setAdapter(
        ArrayAdapter(
            context,
            android.R.layout.simple_spinner_dropdown_item,
            list.map { itemFormatter(it) })
    )

并展示它,或者我可以使用自定义

泡菜

所以现在我在Jetpack Compose中构建了相同的体验,并使用DropDownMenu,它将所有这些项目加载到Column中,当项目数量较少时,它可以正常工作,但是,当涉及到大量项目时,例如,一个列表有超过100个项目,它会下降几帧,并在延迟后显示PopUp
我查看了内部,并试图通过将所有这些文件复制到一个示例项目中,将Column替换为LazyColumn,但这并不像Intrinsic measurements is not yet supported for the Subcomposables那样工作,它抛出异常并失败。

DropdownMenu(
        toggle = toggle,
        expanded = showMenu,
        onDismissRequest = { onDismiss() },
    ) {
        options.forEach{ item ->
            DropdownMenuItem(onClick = {
                onDismiss()
            }) {
                Text(text = item)
            }
        }
    }

如果我使用修改器Modifier.height(200.dp).widht(300.dp)将固定的高度和宽度应用于LazyColumn,则效果非常好
我在问题跟踪器中查找,发现这个issue是相关的,但不相同,建议是做我上面做的事情。
不知道在这里使用什么,因为Compose仍然是新的,不知道哪个组件符合要求。

b4qexyjb

b4qexyjb1#

更新:这上面有一个issue tracker report
您可以尝试其中的解决方案,它也可以工作(如果您还没有一个懒惰列)

DropdownMenu(
    expanded = expanded,
    onDismissRequest = { expanded = false },
) {
    Box(modifier = Modifier.size(width = 100.dp, height = 300.dp)) {
        LazyColumn {
            items(largeList) { item ->
                DropdownMenuItem(
                    text = { Text(text = item) },
                    onClick = {
                        expanded = false
                    },
                )
            }
        }
    }
}

上一个答案

可能有点晚,但我找到了this post
这对我很有效。
在这里添加代码以供将来使用:

@Composable
fun <T> LargeDropdownMenu(
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    label: String,
    notSetLabel: String? = null,
    items: List<T>,
    selectedIndex: Int = -1,
    onItemSelected: (index: Int, item: T) -> Unit,
    selectedItemToString: (T) -> String = { it.toString() },
    drawItem: @Composable (T, Boolean, Boolean, () -> Unit) -> Unit = { item, selected, itemEnabled, onClick ->
        LargeDropdownMenuItem(
            text = item.toString(),
            selected = selected,
            enabled = itemEnabled,
            onClick = onClick,
        )
    },
) {
    var expanded by remember { mutableStateOf(false) }

    Box(modifier = modifier.height(IntrinsicSize.Min)) {
        OutlinedTextField(
            label = { Text(label) },
            value = items.getOrNull(selectedIndex)?.let { selectedItemToString(it) } ?: "",
            enabled = enabled,
            modifier = Modifier.fillMaxWidth(),
            trailingIcon = {
                val icon = expanded.select(Icons.Filled.ArrowDropUp, Icons.Filled.ArrowDropDown)
                Icon(icon, "")
            },
            onValueChange = { },
            readOnly = true,
        )

        // Transparent clickable surface on top of OutlinedTextField
        Surface(
            modifier = Modifier
                .fillMaxSize()
                .padding(top = 8.dp)
                .clip(MaterialTheme.shapes.extraSmall)
                .clickable(enabled = enabled) { expanded = true },
            color = Color.Transparent,
        ) {}
    }

    if (expanded) {
        Dialog(
            onDismissRequest = { expanded = false },
        ) {
            MyTheme {
                Surface(
                    shape = RoundedCornerShape(12.dp),
                ) {
                    val listState = rememberLazyListState()
                    if (selectedIndex > -1) {
                        LaunchedEffect("ScrollToSelected") {
                            listState.scrollToItem(index = selectedIndex)
                        }
                    }

                    LazyColumn(modifier = Modifier.fillMaxWidth(), state = listState) {
                        if (notSetLabel != null) {
                            item {
                                LargeDropdownMenuItem(
                                    text = notSetLabel,
                                    selected = false,
                                    enabled = false,
                                    onClick = { },
                                )
                            }
                        }
                        itemsIndexed(items) { index, item ->
                            val selectedItem = index == selectedIndex
                            drawItem(
                                item,
                                selectedItem,
                                true
                            ) {
                                onItemSelected(index, item)
                                expanded = false
                            }

                            if (index < items.lastIndex) {
                                Divider(modifier = Modifier.padding(horizontal = 16.dp))
                            }
                        }
                    }
                }
            }
        }
    }
}

@Composable
fun LargeDropdownMenuItem(
    text: String,
    selected: Boolean,
    enabled: Boolean,
    onClick: () -> Unit,
) {
    val contentColor = when {
        !enabled -> MaterialTheme.colorScheme.onSurface.copy(alpha = ALPHA_DISABLED)
        selected -> MaterialTheme.colorScheme.primary.copy(alpha = ALPHA_FULL)
        else -> MaterialTheme.colorScheme.onSurface.copy(alpha = ALPHA_FULL)
    }

    CompositionLocalProvider(LocalContentColor provides contentColor) {
        Box(modifier = Modifier
            .clickable(enabled) { onClick() }
            .fillMaxWidth()
            .padding(16.dp)) {
            Text(
                text = text,
                style = MaterialTheme.typography.titleSmall,
            )
        }
    }
}

使用方法:

var selectedIndex by remember { mutableStateOf(-1) }
LargeDropdownMenu(
    label = "Sample",
    items = listOf("Item 1", "Item 2", "Item 3"),
    selectedIndex = selectedIndex,
    onItemSelected = { index, _ -> selectedIndex = index },
)

相关问题