Compose 1.7.0及以上自定义输入法适配:替代弃用的LocalTextInputService
Compose 1.7.0 自定义输入服务适配方案
问题背景
Compose 1.7.0 中LocalTextInputService和TextInputService已被弃用,原有依赖这些API实现的自定义TextField无法再通过CoreTextField获取LocalTextInputService.current实例。官方标注需用PlatformTextInputModifierNode替代,但缺少明确落地指引。
一、过渡兼容方案(基于旧API适配)
如果暂时不想大规模重构,可通过官方遗留适配器兼容原有逻辑,修改你的MyKeyboardContainer实现如下:
@Composable fun MyKeyboardContainer( modifier: Modifier = Modifier, closeKeyboardClickOutside: Boolean = true, content: @Composable ColumnScope.() -> Unit, ) = Column(modifier = modifier) { val focusManager = LocalFocusManager.current val clickableModifier = if (closeKeyboardClickOutside) { Modifier.clickable( interactionSource = remember { MutableInteractionSource() }, indication = null ) { focusManager.clearFocus(force = true) } } else { Modifier } // 替换原有MyLocalTextInputService的获取逻辑 val legacyAdapter = remember { createLegacyPlatformTextInputServiceAdapter() } val myPlatformService = remember { MyPlatformTextInputService() } val textInputService = remember { TextInputService(object : PlatformTextInputService by myPlatformService { // 委托原有状态管理逻辑,同时通过适配器兼容遗留API override fun startInput( value: TextFieldValue, imeOptions: ImeOptions, onEditCommand: (List<EditCommand>) -> Unit, onImeActionPerformed: (ImeAction) -> Unit, ) { myPlatformService.startInput(value, imeOptions, onEditCommand, onImeActionPerformed) legacyAdapter.startInput(value, imeOptions, onEditCommand, onImeActionPerformed) } override fun stopInput() { myPlatformService.stopInput() legacyAdapter.stopInput() } override fun updateState(oldValue: TextFieldValue?, newValue: TextFieldValue) { myPlatformService.updateState(oldValue, newValue) legacyAdapter.updateState(oldValue, newValue) } override fun showSoftwareKeyboard() { myPlatformService.showSoftwareKeyboard() legacyAdapter.showSoftwareKeyboard() } override fun hideSoftwareKeyboard() { myPlatformService.hideSoftwareKeyboard() legacyAdapter.hideSoftwareKeyboard() } }) } CompositionLocalProvider(LocalTextInputService provides textInputService) { Column( modifier = Modifier .weight(1f) .fillMaxWidth() .then(clickableModifier), content = content, ) MyKeyboard(windowSize) } }
该方案完整保留你原有MyPlatformTextInputService的状态管理逻辑,同时通过委托机制满足CoreTextField的API调用要求。
二、正式替代方案(基于PlatformTextInputModifierNode)
官方推荐的PlatformTextInputModifierNode采用Modifier节点架构,需将输入服务逻辑从CompositionLocal迁移至Modifier体系,具体步骤如下:
1. 重构输入状态管理类
剥离原有PlatformTextInputService继承关系,保留核心状态管理逻辑:
internal class MyInputStateManager { val softKeyboardState = MutableStateFlow(MyPlatformTextInputService.KeyboardState.HIDDEN) val inputState = MutableStateFlow<MyPlatformTextInputService.InputState>(MyPlatformTextInputService.InputState.Idle) fun hideSoftwareKeyboard() { softKeyboardState.value = MyPlatformTextInputService.KeyboardState.HIDDEN } fun showSoftwareKeyboard() { softKeyboardState.value = MyPlatformTextInputService.KeyboardState.SHOWN } fun startInput( value: TextFieldValue, imeOptions: ImeOptions, onEditCommand: (List<EditCommand>) -> Unit, onImeActionPerformed: (ImeAction) -> Unit, ) { inputState.value = MyPlatformTextInputService.InputState.Active( textFieldValue = value, onEditCommand = onEditCommand, onImeActionPerformed = onImeActionPerformed, imeOptions = imeOptions, ) softKeyboardState.value = MyPlatformTextInputService.KeyboardState.SHOWN } fun stopInput() { inputState.value = MyPlatformTextInputService.InputState.Idle } fun updateState(oldValue: TextFieldValue?, newValue: TextFieldValue) { (inputState.value as? MyPlatformTextInputService.InputState.Active)?.let { activeInputState -> inputState.value = activeInputState.copy(textFieldValue = newValue) } } }
2. 实现自定义PlatformTextInputModifierNode
创建自定义Modifier节点,关联状态管理类并实现官方接口:
internal class MyTextInputNode( private val inputStateManager: MyInputStateManager ) : ModifierNode, PlatformTextInputModifierNode { private var textInputSession: PlatformTextInputSession? = null override val platformTextInputSession: PlatformTextInputSession? get() = textInputSession override fun onDetach() { textInputSession?.close() textInputSession = null } override fun requestSoftwareKeyboardShow() { inputStateManager.showSoftwareKeyboard() } override fun requestSoftwareKeyboardHide() { inputStateManager.hideSoftwareKeyboard() } override fun startInput( value: TextFieldValue, imeOptions: ImeOptions, onEditCommand: (List<EditCommand>) -> Unit, onImeActionPerformed: (ImeAction) -> Unit ) { inputStateManager.startInput(value, imeOptions, onEditCommand, onImeActionPerformed) // 创建输入会话,处理系统IME交互(按需实现) textInputSession = object : PlatformTextInputSession { override fun updateState(newValue: TextFieldValue) { inputStateManager.updateState(null, newValue) } override fun close() { inputStateManager.stopInput() } } } override fun stopInput() { inputStateManager.stopInput() textInputSession?.close() textInputSession = null } override fun updateInputState(oldValue: TextFieldValue?, newValue: TextFieldValue) { inputStateManager.updateState(oldValue, newValue) } } // 扩展Modifier方法,简化使用 fun Modifier.myTextInputService(inputStateManager: MyInputStateManager): Modifier = this then modifierNodeOf { MyTextInputNode(inputStateManager) }
3. 修改MyKeyboardContainer使用新架构
移除CompositionLocal依赖,改为通过Modifier注入输入服务:
@Composable fun MyKeyboardContainer( modifier: Modifier = Modifier, closeKeyboardClickOutside: Boolean = true, content: @Composable ColumnScope.(MyInputStateManager) -> Unit, ) = Column(modifier = modifier) { val focusManager = LocalFocusManager.current val clickableModifier = if (closeKeyboardClickOutside) { Modifier.clickable( interactionSource = remember { MutableInteractionSource() }, indication = null ) { focusManager.clearFocus(force = true) } } else { Modifier } val inputStateManager = remember { MyInputStateManager() } Column( modifier = Modifier .weight(1f) .fillMaxWidth() .then(clickableModifier) .myTextInputService(inputStateManager), ) { content(inputStateManager) } MyKeyboard(windowSize) }
4. 自定义TextField适配
在你的自定义TextField组件中,直接应用该Modifier即可让CoreTextField通过节点获取输入服务。
方案说明
- 过渡方案可快速兼容现有代码,但属于临时妥协,后续版本可能移除遗留API
- 正式方案符合Compose最新架构设计,基于Modifier节点的实现更贴合组件化状态管理理念,推荐逐步迁移
内容的提问来源于stack exchange,提问作者MisterFlyBear
相关产品推荐
相关产品推荐

