Text Field with Chips in jetpack compose

我正在努力实现与照片类似的行为.一个可以做同样事情的库也会很有用. 我已经试过了 https://github.com/dokar3/ChipTextField个 但也遇到了一些问题

java.lang.NoClassDefFoundError: Failed resolution of: Landroidx/compose/ui/platform/LocalSoftwareKeyboardController;

推荐答案

您可以使用FlowRowChipBasicTextField来实现它.

enter image description here

1-创建包含URI和字符串的数据类

@Immutable
data class ChipData(
    val uri: Uri,
    val text: String,
    val id: String = UUID.randomUUID().toString()
)

2-创建显示图像、字符串的自定义芯片.我用Coil库为画家从Uri得到了Painter.

@Composable
private fun MyChip(
    backgroundColor: Color,
    data: ChipData,
    onDeleteClick: () -> Unit
) {
    Chip(
        modifier = Modifier,
        shape = RoundedCornerShape(50),
        enabled = false,
        onClick = {},
        border = BorderStroke(1.dp, Green400.copy(alpha = .9f)),
        colors = ChipDefaults.chipColors(
            disabledBackgroundColor = backgroundColor,
            disabledContentColor = Color.White
        ),
        leadingIcon = {
            Image(
                painter = rememberAsyncImagePainter(data.uri),
                modifier = Modifier
                    .padding(vertical = 4.dp)
                    .size(34.dp)
                    .clip(CircleShape),
                contentScale = ContentScale.FillBounds,
                contentDescription = null
            )
        }
    ) {
        Text(
            text = data.text,
            modifier = Modifier.weight(1f, fill = false),
            overflow = TextOverflow.Ellipsis,
            maxLines = 1
        )
        Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing))
        Icon(
            modifier = Modifier
                .clip(CircleShape)
                .clickable {
                    onDeleteClick()
                }
                .background(Color.Black.copy(alpha = .4f))
                .size(16.dp)
                .padding(2.dp),
            imageVector = Icons.Filled.Close,
            tint = Color(0xFFE0E0E0),
            contentDescription = null
        )
    }
}

3-使用FlowRow对齐筹码,并将BasicTextfield放在最后一项.

此外,我还使用了Memory LauncherForActivityResult来 Select 可以添加到Gradle的图像

implementation("com.google.modernstorage:modernstorage-photopicker:1.0.0-alpha06")

如果需要,您可以在SAF中使用其他或默认图像拾取器

@OptIn(ExperimentalLayoutApi::class)
@Composable
fun ChipAndTextFieldLayout(
    modifier: Modifier = Modifier,
    backgroundColor: Color,
    list: List<ChipData> = emptyList(),
    onChipCreated: (ChipData) -> Unit,
    chip: @Composable (data: ChipData, index: Int) -> Unit
) {

    var text by remember {
        mutableStateOf("")
    }

    val focusRequester = remember {
        FocusRequester()
    }

    val keyboardController: SoftwareKeyboardController? = LocalSoftwareKeyboardController.current

    val photoPicker =
        rememberLauncherForActivityResult(PhotoPicker()) { uris ->
            uris.firstOrNull()?.let { uri: Uri ->
                onChipCreated(
                    ChipData(
                        uri = uri,
                        text = text
                    )
                )
                text = ""
                // Open keyboard after new chip is added
                keyboardController?.show()
            }
        }

    LaunchedEffect(Unit) {
        delay(100)
        focusRequester.requestFocus()
    }

    FlowRow(
        modifier = modifier
            .drawWithContent {
                drawContent()
                drawLine(
                    Green400.copy(alpha = .6f),
                    start = Offset(0f, size.height),
                    end = Offset(size.width, size.height),
                    strokeWidth = 4.dp.toPx()
                )
            },
        horizontalArrangement = Arrangement.spacedBy(6.dp)
    ) {

        list.forEachIndexed { index, item ->
            key(item.id) {
                chip(item, index)
            }
        }

        Box(
            modifier = Modifier.height(54.dp)
                // This minimum width that TextField can have
                // if remaining space in same row is smaller it's moved to next line
                .widthIn(min = 80.dp)
                // TextField can grow as big as Composable width
                .weight(1f),
            contentAlignment = Alignment.CenterStart
        ) {
            BasicTextField(
                modifier = Modifier.focusRequester(focusRequester),
                value = text,
                textStyle = TextStyle(
                    fontSize = 20.sp
                ),
                cursorBrush = SolidColor(backgroundColor),
                singleLine = true,
                onValueChange = { text = it },
                keyboardOptions = KeyboardOptions(
                    imeAction = ImeAction.Done
                ),
                keyboardActions = KeyboardActions(
                    onDone = {
                        if (text.isNotEmpty()) {
                            keyboardController?.hide()
                            photoPicker.launch(
                                PhotoPicker.Args(
                                    PhotoPicker.Type.IMAGES_ONLY, 1
                                )
                            )
                        }
                    }
                )
            )
        }
    }
}

用法

@Preview
@Composable
private fun ChipSampleAndTextLayoutSample() {

    val backgroundColor = Green400.copy(alpha = .6f)

    val chipDataSnapshotStateList = remember {
        mutableStateListOf<ChipData>()
    }

    ChipAndTextFieldLayout(
        modifier = Modifier.fillMaxWidth().padding(8.dp),
        list = chipDataSnapshotStateList,
        backgroundColor = backgroundColor,
        onChipCreated = {
            chipDataSnapshotStateList.add(it)
        },

        chip = { data: ChipData, index: Int->
            MyChip(backgroundColor, data){
                chipDataSnapshotStateList.removeAt(index)
            }
        }
    )
}

Android相关问答推荐

Jetpack DataStore原生lib已添加到Bundle 包:libdatastore_share_counter.so-那是什么?

如何允许我的应用程序在Android 10上运行,同时目标是API 33

如何制作带有图标和文本的Fab

Android 12+BLE字节不同

仅当先前输入为 yes 时,Android 才会要求下一个输入

我需要在房间数据库中保留旧的自动迁移行吗?

如何正确创建可拖动的浮动视图?

有没有办法让协程通道在接收时遵循特定的顺序而不是先进先出

Spinner - onItemLongClick 从未执行

NFC getNdefMessage 在 Android 13 上写入标签后返回 null

为什么我要使用 $version 而不是2.7.0?

MediumTopAppBar Material3 只更改大标题

如何在最后一个可见项目之后计算惰性列中的空白空间

如何对齐文本和图标可组合,以便即使在文本溢出后它们也能保持在一起?

如何在jetpack compose中创建水印文字效果

TextField 溢出和软包装不适用于 Compose 约束布局

如何将房间数据库导出到 .CSV

设备文件资源管理器-ROOM 数据库中的数据库文件夹为空

如何使用 Glide 将图像下载到设备内部存储

如何在android studio 2021.1中使用谷歌库以外的库