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

Android Compose开发如何在软键盘上方显示粗体、斜体、下划线格式按钮

Jetpack Compose 软键盘上方富文本格式化按钮实现方案

完全可行,核心是通过WindowInsets监听软键盘状态,结合TextFieldValue的原生富文本能力实现,具体步骤如下:

前置配置

首先在Activity的onCreate方法中添加如下配置,确保Compose可以正确获取软键盘高度信息:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // 关闭系统默认窗口适配,交给Compose处理Insets
    WindowCompat.setDecorFitsSystemWindows(window, false)
    setContent {
        // 你的Compose页面内容
    }
}

完整实现代码

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.FormatBold
import androidx.compose.material.icons.filled.FormatItalic
import androidx.compose.material.icons.filled.FormatUnderlined
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardOptions
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.ime
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.platform.LocalDensity

@Composable
fun RichTextInputPage() {
    val keyboardController = LocalSoftwareKeyboardController.current
    var textValue by remember { mutableStateOf(TextFieldValue("Write your text...")) }
    // 监听软键盘是否弹出
    val isImeVisible = WindowInsets.ime.getBottom(LocalDensity.current) > 0

    Column(
        modifier = Modifier
            .fillMaxSize()
            .systemBarsPadding()
    ) {
        TextField(
            value = textValue,
            modifier = Modifier
                .padding(16.dp)
                .fillMaxWidth()
                .weight(1f),
            placeholder = { Text(text = "John Doe") },
            textStyle = TextStyle(
                color = Color.Gray,
                fontSize = 20.sp
            ),
            onValueChange = {
                textValue = it
            },
            keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
            keyboardActions = KeyboardActions(
                onDone = {
                    keyboardController?.hide()
                    // 自定义后续逻辑
                }
            )
        )

        // 仅当软键盘弹出时显示格式化工具栏
        if (isImeVisible) {
            Row(
                modifier = Modifier
                    .fillMaxWidth()
                    .background(MaterialTheme.colorScheme.surface)
                    .imePadding()
                    .padding(horizontal = 8.dp),
                horizontalArrangement = Arrangement.Start
            ) {
                // 加粗按钮
                IconButton(onClick = {
                    val selection = textValue.selection
                    if (selection.start != selection.end) {
                        val newText = buildAnnotatedString {
                            append(textValue.annotatedString)
                            addStyle(
                                style = SpanStyle(fontWeight = FontWeight.Bold),
                                start = selection.start,
                                end = selection.end
                            )
                        }
                        textValue = textValue.copy(annotatedString = newText)
                    }
                }) {
                    Icon(Icons.Default.FormatBold, contentDescription = "加粗")
                }
                // 斜体按钮
                IconButton(onClick = {
                    val selection = textValue.selection
                    if (selection.start != selection.end) {
                        val newText = buildAnnotatedString {
                            append(textValue.annotatedString)
                            addStyle(
                                style = SpanStyle(fontStyle = FontStyle.Italic),
                                start = selection.start,
                                end = selection.end
                            )
                        }
                        textValue = textValue.copy(annotatedString = newText)
                    }
                }) {
                    Icon(Icons.Default.FormatItalic, contentDescription = "斜体")
                }
                // 下划线按钮
                IconButton(onClick = {
                    val selection = textValue.selection
                    if (selection.start != selection.end) {
                        val newText = buildAnnotatedString {
                            append(textValue.annotatedString)
                            addStyle(
                                style = SpanStyle(textDecoration = TextDecoration.Underline),
                                start = selection.start,
                                end = selection.end
                            )
                        }
                        textValue = textValue.copy(annotatedString = newText)
                    }
                }) {
                    Icon(Icons.Default.FormatUnderlined, contentDescription = "下划线")
                }
            }
        }
    }
}

说明

  • 以上代码基于Compose Material 3实现,如果你使用Material 2,替换对应的图标和主题色配置即可
  • 样式修改逻辑默认是叠加样式,如果需要支持取消已添加的格式,可在点击按钮时先判断选中区间是否存在对应样式,存在则移除即可
  • 富文本内容可根据需求转成HTML或Markdown格式持久化存储

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 10:24:04