You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose:如何获取BasicTextField选中文字长度并触发弹窗?

在Jetpack Compose中获取BasicTextField选中文字并显示弹窗

我需要实现这样的功能:在Jetpack Compose的BasicTextField中获取选中文字的数量,判断是否有文字被选中,若有则显示弹窗。我尝试过使用SelectionContainer的方案,但没有效果。以下是我的相关实现代码:

@Composable
fun AddEditNoteScreen(
    modifier: Modifier = Modifier,
    onBack: () -> Unit,
    onShowSnackbar: suspend (String) -> Boolean,
    viewModel: AddNoteViewModel = hiltViewModel()
) {
    val state by viewModel.uiState.collectAsStateWithLifecycle()
    val scope = rememberCoroutineScope()
    val scrollState = rememberScrollState()
    val focusManager = LocalFocusManager.current
    val openDatePicker = remember {
        mutableStateOf(false)
    }

    var titleValue: TextFieldValue by remember { mutableStateOf(value = TextFieldValue()) }
    var descriptionValue: TextFieldValue by remember { mutableStateOf(value = TextFieldValue()) }

    var openEditContentsHolder by remember {
        mutableStateOf(false)
    }

    val openCloseDialog = remember {
        mutableStateOf(false)
    }

    val showTimePicker = remember { mutableStateOf(false) }
    val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
    val showBottomSheet = remember { mutableStateOf(false) }
    BoxWithConstraints(
        modifier = modifier
            .fillMaxSize(),
        contentAlignment = Alignment.BottomCenter
    ) {
        when (val uiState = state) {
            is AddNoteUiState.Data -> {
                LaunchedEffect(key1 = uiState.createOrUpdateNoteStatus) {
                    if (uiState.createOrUpdateNoteStatus) {
                        scope.launch { onShowSnackbar(uiState.actionMessage) }
                    }
                }
                LaunchedEffect(key1 = uiState.error) {
                    if (uiState.error.isNotEmpty()) {
                        scope.launch {
                            onShowSnackbar(uiState.error)
                        }
                    }
                }
                LaunchedEffect(key1 = uiState.note) {
                    titleValue = TextFieldValue(uiState.note.title)
                    descriptionValue = TextFieldValue(uiState.note.description ?: "")
                }

                val maxHeight = maxHeight
                Column(
                    modifier = modifier
                        .fillMaxSize()
                        .padding(28.dp)
                        .verticalScroll(scrollState),
                    verticalArrangement = Arrangement.spacedBy(40.dp)
                ) {
                    Header(onBack = {
                        viewModel.updateNote(
                            uiState.note.copy(
                                title = titleValue.text,
                                description = descriptionValue.text
                            )
                        )
                        if (uiState.dueDate == null || uiState.note.title.isEmpty()) {
                            openCloseDialog.value = true
                            return@Header
                        }
                        viewModel.addNote()
                        onBack()
                    }, onSave = {
                        scope.launch {
                            focusManager.clearFocus()
                            delay(200)
                            showBottomSheet.value = true
                        }
                    })
                    CategorySection(uiState = uiState) {
                        viewModel.selectCategory(it)
                    }

                    Surface(
                        modifier = modifier.weight(1f),
                        shape = RoundedCornerShape(topStart = 24.dp, topEnd = 24.dp),
                        color = MaterialTheme.colorScheme.background,
                        shadowElevation = 1.dp
                    ) {
                        Column(
                            modifier = modifier
                                .fillMaxSize()
                                .padding(16.dp),
                            verticalArrangement = Arrangement.spacedBy(10.dp),
                            horizontalAlignment = Alignment.CenterHorizontally
                        ) {
                            NoteBasicTextField(
                                value = titleValue,
                                updateTextValue = {
                                    titleValue = it
                                    val selectedTextLength = it.selection.max - it.selection.min
                                    openEditContentsHolder = selectedTextLength > 0
                                },
                                textStyle = MaterialTheme.typography.headlineSmall.copy(fontSize = 20.sp),
                                placeholder = "Enter title",
                                keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
                            )

                            NoteBasicTextField(
                                value = descriptionValue,
                                updateTextValue = {
                                    descriptionValue = it
                                    val selectedTextLength = it.selection.max - it.selection.min
                                    openEditContentsHolder = selectedTextLength > 0
                                },
                                textStyle = MaterialTheme.typography.labelLarge.copy(fontSize = 13.sp),
                                placeholder = "Enter description",
                                keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
                            )

                            Column(
                                modifier = modifier.fillMaxWidth(),
                                horizontalAlignment = Alignment.CenterHorizontally,
                                verticalArrangement = Arrangement.spacedBy(4.dp)
                            ) {
                                DatePickerInDatePickerDialog(
                                    openDialog = openDatePicker.value,
                                    onDismiss = { openDatePicker.value = false },
                                    selectedDate = { date ->
                                        date?.let {
                                            if (Instant.fromEpochMilliseconds(it)
                                                    .toLocalDateTime(TimeZone.currentSystemDefault()).date < Clock.System.now()
                                                    .toLocalDateTime(
                                                        TimeZone.currentSystemDefault()
                                                    ).date
                                            ) {
                                                scope.launch {
                                                    onShowSnackbar("Date is not valid")
                                                }
                                                return@let
                                            }
                                            viewModel.updateDueDate(
                                                Instant.fromEpochMilliseconds(it)
                                                    .toLocalDateTime(
                                                        TimeZone.currentSystemDefault()
                                                    ).date
                                            )
                                            scope.launch {
                                                onShowSnackbar("Date is selected")
                                            }
                                        }
                                    })
                            }
                            Column(
                                modifier = modifier.fillMaxWidth(),
                                horizontalAlignment = Alignment.CenterHorizontally,
                                verticalArrangement = Arrangement.spacedBy(4.dp)
                            ) {
                                TimePickerWithDialog(
                                    showTimePicker = showTimePicker.value,
                                    timePickerState = {
                                        viewModel.updateDueTime(
                                            time = TimeModel(
                                                it.hour,
                                                it.minute
                                            )
                                        )
                                    },
                                    onDismiss = { showTimePicker.value = false })

                            }
                        }
                    }


                }
                DateTimeSheet(
                    showBottomSheet,
                    modifier,
                    maxHeight,
                    sheetState,
                    uiState,
                    openDatePicker,
                    showTimePicker
                )

                CloseDialog(openCloseDialog, modifier, onBack)

            }
        }
        AnimatedVisibility(visible = openEditContentsHolder) {
            focusManager.clearFocus()
            Box(
                modifier = modifier
                    .fillMaxWidth()

                    .padding(20.dp)
            ) {
                Surface(
                    modifier = modifier
                        .fillMaxWidth()
                        .height(56.dp),
                    shape = RoundedCornerShape(41.dp),
                    color = MaterialTheme.colorScheme.scrim,
                    shadowElevation = 8.dp
                ) {
                    Row(
                        modifier = modifier.fillMaxWidth(),
                        horizontalArrangement = Arrangement.SpaceAround,
                        verticalAlignment = Alignment.CenterVertically
                    ) {
                        Icon(
                            painter = painterResource(id = com.sn.designsystem.R.drawable.edit),
                            contentDescription = "edit"
                        )
                    }
                }
            }
        }
    }
}
@Composable
fun NoteBasicTextField(
    modifier: Modifier = Modifier,
    readOnly: Boolean = false,
    value: TextFieldValue,
    height: Dp = 54.dp,
    borderWidth: Dp = 1.dp,
    borderColor: Color = Color.Unspecified,
    borderShape: Shape = RoundedCornerShape(size = 5.dp),
    updateTextValue: (TextFieldValue) -> Unit,
    textStyle: TextStyle = TextStyle(
        fontSize = 16.sp,
        fontWeight = FontWeight.Medium,
        color = Color.DarkGray
    ),
    contentAlignment: Alignment = Alignment.CenterStart,
    visualTransformation: VisualTransformation = VisualTransformation.None,
    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
    keyboardActions: KeyboardActions = KeyboardActions.Default,
    singleLine: Boolean = false,
    label: @Composable (() -> Unit)? = null,
    placeholder: String = "",
    leadingIcon: @Composable (() -> Unit)? = null,
    trailingIcon: @Composable (() -> Unit)? = null,
) {
    Column(modifier = modifier.height(height)) {
        label?.let { it() }
        BasicTextField(
            modifier = modifier.fillMaxSize(),
            readOnly = readOnly,
            value = value,
            onValueChange = {
                updateTextValue(it)
            },
            visualTransformation = visualTransformation,
            keyboardActions = keyboardActions,
            keyboardOptions = keyboardOptions,
            singleLine = singleLine,
            textStyle = textStyle,
            decorationBox = { innerTextField ->
                Box(
                    modifier = Modifier
                        .fillMaxSize()
                        .border(
                            width = borderWidth,
                            color = borderColor,
                            shape = borderShape
                        )
                        .padding(horizontal = 16.dp, vertical = 8.dp),
                    contentAlignment = contentAlignment // Center the content vertically
                ) {
                    Row(
                        modifier = Modifier.fillMaxWidth(),
                        verticalAlignment = Alignment.CenterVertically,
                        horizontalArrangement = Arrangement.spacedBy(4.dp)
                    ) {
                        leadingIcon?.let { it() }
                        Box(
                            modifier = Modifier
                                .weight(1f)
                        ) {
                            if (value.text.isEmpty()) {
                                Text(
                                    text = placeholder,
                                    style = LocalTextStyle.current.copy(
                                        fontSize = 16.sp,
                                        color = MaterialTheme.colorScheme.outline
                                    ),
                                )
                            }
                            innerTextField()
                        }
                        trailingIcon?.let { it() }
                    }
                }
            }
        )
    }
}

内容的提问来源于stack exchange,提问作者Saeed Noshadi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 03:39:51