下拉式框架落下和滞后在JetPack组成

发布于 2025-01-23 18:18:50 字数 1504 浏览 0 评论 0原文

所以我现在在泡菜里。

我有

我有国家的列表,我想允许用户通过显示下降菜单来选择它们,而早些时查看说view.setupdropdown,此inturn加载list popupupwindow并将其固定在当前视图中,并显示所有项目,并且在没有jank或jank或jank或任何框架下降。

喜欢

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

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

泡菜

所以现在我在jetpack构图中建立了相同的体验,并使用dropdownmenu,它加载了所有这些项目在项目数量较少时正常工作,但是,当涉及大量项目时,列表的列表却更多的100个项目会删除几帧,并显示<代码>弹出延迟后。

我查找内部,并试图用lazycolumn将所有这些文件中的所有这些文件复制到示例项目中 固有的测量值尚未支持子组件,并且会引发和异常和失败。

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

如果我使用Modifier modifier.height(200.dp).widht(300.dp)

我查找 ,如果我将固定高度和宽度应用于lazycolumn,它的工作正常非常好。在问题跟踪器中,并找到了此问题我在上面做了什么。

不确定在这里使用什么,因为撰写仍然是新的,不知道哪个组件适合该账单。

So I am bit of in a pickle now.

The Begining

I have list of countries and I want to allow the user to pick any of them by showing a drop a down menu, and earlier no jetpack compose way, I had a an extension on View say View.setupDropDown and this inturn loads up a ListPopupWindow and anchors it to the current view, and shows all the items and works perfectly fine without jank or any frame drop.

like

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

and show it, or I can use a custom

The Pickle

So now I am building the same experience in Jetpack Compose, and Using DropDownMenu and it loads up all those items in a Column which works fine when Items are less in number, but, when it comes to large number of items like, a list which has more then 100 items, it drops a few frames, and shows the PopUp after a delay.

I looked up insides and tried to replace the Column with LazyColumn by copying in all those files to a sample project but that doest work as
Intrinsic measurements is not yet supported for the Subcomposables and it throws and exception and fails.

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

It works perfectly fine If I apply fixed height and width to the LazyColumn, using the modifier Modifier.height(200.dp).widht(300.dp)

I looked up in issue tracker, and found this issue which was relevant but not same, and the suggestion was to do what I did above.

Not sure what to use in here, as Compose is still new, don't know which component fits the bill.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

哽咽笑 2025-01-30 18:18:50

更新:有一个问题跟踪器报告

您可以尝试内部也有效的解决方案(如果您还没有懒惰的列)

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
                    },
                )
            }
        }
    }
}

先前的答案

可能有点晚了,但是我发现这篇文章

对我有用。

将来在此处添加代码:

    @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 },
)

Update: There is an issue tracker report on this.

You can try the solution inside which also works (if you don't already have a lazy column)

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
                    },
                )
            }
        }
    }
}

Previous answer

It may be a little late but I found this post

That worked for me.

Adding the code here for the future:

    @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,
            )
        }
    }
}

Usage:

var selectedIndex by remember { mutableStateOf(-1) }
LargeDropdownMenu(
    label = "Sample",
    items = listOf("Item 1", "Item 2", "Item 3"),
    selectedIndex = selectedIndex,
    onItemSelected = { index, _ -> selectedIndex = index },
)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文