本文译自「Rich Content in Text Input in Jetpack Compose」,原文链接https://medium.com/proandroiddev/rich-content-in-text-input-in-jetpack-compose-0f4c1e8e830f,由Oğuzhan Aslan发布于2026年3月23日。
引言
在当今的移动环境中,文本输入不再仅仅局限于文本。用户已经习惯了丰富且富有表现力的沟通方式,而不仅仅局限于简单的字符。无论是发送有趣的 GIF、分享贴纸,还是从其他应用拖放图片,富文本支持都已成为用户的默认期望。
大多数流行的即时通讯和社交媒体应用都能无缝支持这些功能。然而,对于 Android 开发者来说,支持这种“默认”行为需要特定的实现步骤。标准的文本字段无法自动处理从 Gboard 发送的 GIF 或从剪贴板粘贴的图片。
“默认”体验(以及它为何失败)
如果你只是将一个 TextField 拖放到 Compose UI 中,它就能完美地处理文本。但是,如果你尝试从键盘插入 GIF 或粘贴图片,却发现……没有任何反应。运气好的话,键盘可能会提交一个 URI 字符串;但更常见的情况是,输入会被直接忽略,因为文本字段只接受文本。

为了解决这个问题,Jetpack Compose 引入了一个强大的修饰符:contentReceiver。
解决方案:contentReceiver
contentReceiver 修饰符是一个统一的 API,旨在处理来自多个来源的富文本内容:
软键盘:来自 Gboard 等应用的 GIF 和贴纸。
剪贴板:粘贴的图片或富文本。
拖放:从其他应用(在分屏模式下)或同一应用内拖拽的内容。
contentReceiver 为我们提供了一个单一的入口点来处理所有 TransferableContent,而无需为键盘管理 OnCommitContentListener,也无需为拖放监听器单独管理。
逐步实现
让我们构建一个可以接收和显示图片的文本输入区域。
步骤 1:ViewModel 逻辑
首先,我们需要一种方法来处理传入的内容。我们将创建一个 RichContentViewModel 来处理 TransferableContent。核心逻辑涉及使用 .consume 函数,该函数允许我们提取可以处理的内容部分(例如图片 URI),并返回其余部分(如果已处理完所有内容,则返回 null)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | |
步骤 2:UI 实现
现在,让我们将其应用到 UI 中。contentReceiver 的一个关键优势是灵活性。我们不必将其直接应用于 TextField。通过将其应用于父容器(例如 Column),我们可以将整个区域转换为拖放操作的“放置区”,从而改善用户体验。
以下是我们的 RichContentTextField 可组合组件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | |
代码要点:
**contentReceiver**在父级上:我们将修饰符放在了Column上。这意味着如果用户将图像拖到此框中的任何位置,它都会被捕获。**AsyncImage**:我们使用 Coil 的AsyncImage来渲染提取的 URI。关注点分离:UI 只负责显示状态(
selectedImages),而 ViewModel 则处理TransferableContent的复杂性。
结果
只需几行代码,我们就将一个基本的文本输入框转换成了一个富媒体接收器。用户现在可以从键盘插入 GIF 动画,或者直接将照片拖到应用中。

结论
支持富媒体内容不再是“额外”功能,而是现代 Android 应用开发的核心组成部分。Jetpack Compose 中的 contentReceiver 修饰符极大地简化了这一过程,将原本三个独立的 API 统一到一个简洁的声明式接口中。通过实现这一点,你可以确保你的应用拥有原生应用般的体验,并且能够响应用户如今的实际交互方式。