在这里插入图片描述

1 -> 概述:自定义键盘交互体验的关键一跃

在鸿蒙应用开发中,自定义键盘(Custom Keyboard)一直是提升输入体验与保障数据安全的重要手段。通过 TextInputTextAreaRichEditor 等输入组件的 customKeyboard 属性,开发者可以完全替代系统默认键盘,构建出符合业务场景的专属输入面板——无论是金融级的安全键盘、九宫格数字键盘,还是带表情符号的社交输入键盘。

然而,在鸿蒙 6.0(API 23)之前,自定义键盘在多个输入框之间切换时存在一个令人困扰的体验断层:每当用户从一个输入框切换到另一个输入框时,自定义键盘会先收起再重新弹出。这个「收起-弹出」的过程虽然短暂,但在需要连续填写多个字段的场景下(如表单填写、注册流程、多字段编辑),不仅造成了视觉上的闪烁和割裂感,更打断了用户的输入节奏,影响了操作效率与流畅度。

鸿蒙 6.0 通过 UIContext 新增的 setCustomKeyboardContinueFeature 接口,彻底解决了这一痛点。该接口允许开发者设置自定义键盘在输入框之间切换时是否接续——即当用户在多个绑定了自定义键盘的输入框之间切换焦点时,键盘可以保持展开状态而不收回。这一能力虽然看似简单,却标志着鸿蒙自定义键盘体系从「能用」迈向「好用」的关键一步,对于追求极致交互体验的应用而言意义重大。

本文将从接口定义、使用场景、代码实现、注意事项等多个维度,对 setCustomKeyboardContinueFeature 进行全方位的深入解读。

2 -> setCustomKeyboardContinueFeature 接口详解

2.1 -> 接口基本信息

setCustomKeyboardContinueFeatureUIContext 类在 API version 23 中新增的成员方法。其核心作用是为当前 UI 上下文(UIContext)范围内的自定义键盘设定「接续」行为。

接口签名:

setCustomKeyboardContinueFeature(enable: boolean): void

参数说明:

参数名 类型 必填 说明
enable boolean true 表示启用自定义键盘接续功能;false 表示禁用

系统能力: SystemCapability.ArkUI.ArkUI.Full

支持平台: Phone、PC、2in1、Tablet、TV、Wearable

元服务支持: 从 API version 11 开始,该接口支持在元服务(原子化服务)中使用

2.2 -> 接口的调用方式

该接口需要通过 UIContext 实例进行调用。在鸿蒙 ArkUI 开发中,获取 UIContext 实例主要有三种方式:

方式一:通过自定义组件内置方法获取

@Entry
@Component
struct MyComponent {
  aboutToAppear() {
    const uiContext = this.getUIContext();
    uiContext.setCustomKeyboardContinueFeature(true);
  }
}

方式二:通过 ohos.window 中的 getUIContext() 方法获取

// 在 EntryAbility 中
import { window } from '@kit.ArkUI';

onWindowStageCreate(windowStage: window.WindowStage): void {
  const uiContext = windowStage.getMainWindowSync().getUIContext();
  uiContext.setCustomKeyboardContinueFeature(true);
}

方式三:通过 UIContext 类的静态方法获取

import { UIContext } from '@kit.ArkUI';

const uiContext = UIContext.getCallingScopeUIContext();
uiContext?.setCustomKeyboardContinueFeature(true);

2.3 -> 与 attributeModifier 的协作

值得特别关注的是,从 API version 23 开始,setCustomKeyboardContinueFeature 接口支持在 attributeModifier 中调用。这意味着开发者可以将自定义键盘的接续行为与组件的状态(如焦点态、按压态等)进行联动控制,实现更精细的交互管理。

关于 attributeModifier,它是鸿蒙 ArkUI 提供的一种属性修改器机制,允许开发者将 UI 与样式逻辑分离,通过状态变量触发属性更新。将 setCustomKeyboardContinueFeature 纳入这一体系,为复杂场景下的键盘行为控制提供了更大的灵活性。

3 -> 功能价值与典型使用场景

3.1 -> 为什么需要「接续」?

在深入代码之前,有必要先理解这个功能背后的设计考量。

在未启用接续功能时(即 enable = false 或未调用该接口),自定义键盘的行为逻辑如下:

  1. 输入框 A 获得焦点 → 自定义键盘弹出
  2. 用户点击输入框 B(同样绑定了自定义键盘)→ 输入框 A 失去焦点 → 自定义键盘收起
  3. 输入框 B 获得焦点 → 自定义键盘重新弹出

这一过程存在两个明显的问题:

  • 视觉闪烁:键盘的收起与弹出造成了界面的频繁变化,尤其在页面布局会随键盘避让而调整时,体验尤为割裂。
  • 操作延迟:每次切换都需要等待键盘重新加载和渲染,增加了用户的操作等待时间。

启用接续功能后(enable = true),行为变为:

  1. 输入框 A 获得焦点 → 自定义键盘弹出
  2. 用户点击输入框 B → 输入框 A 失去焦点,输入框 B 获得焦点 → 自定义键盘保持展开状态,不收起
  3. 光标和输入上下文无缝切换到输入框 B

3.2 -> 典型使用场景

场景一:多字段表单

在用户注册、个人信息填写、订单提交等需要连续输入多个字段的场景中,启用键盘接续可以显著提升填写效率。用户无需在姓名、手机号、地址等字段之间反复等待键盘弹起,输入体验更加连贯。

场景二:安全键盘的连续输入

金融类应用通常要求使用自定义安全键盘来防止系统键盘的输入法记录和截屏风险。在涉及多步安全验证(如依次输入卡号、有效期、CVV 码)时,键盘接续可以避免安全键盘频繁收起弹出带来的体验降级。

场景三:富文本编辑

RichEditor 等富文本编辑组件中,用户可能需要在同一页面中编辑多个富文本区域(如文章标题区与正文区),键盘接续能够让编辑过程更加流畅。

场景四:多输入框的聊天或评论界面

在需要同时操作多个输入框的应用中(如主回复框与快捷回复框),键盘接续可以避免不必要的键盘切换,保持用户的操作沉浸感。

4 -> 完整代码示例

4.1 -> 基础用法:启用全局接续

以下示例展示了如何在页面中启用自定义键盘的接续功能,使两个 TextInput 之间切换时键盘保持展开:

// CustomKeyboardContinueExample.ets
import { UIContext } from '@kit.ArkUI';

@Entry
@Component
struct CustomKeyboardContinueExample {
  @State inputValue1: string = '';
  @State inputValue2: string = '';
  private uiContext: UIContext | undefined = undefined;

  aboutToAppear() {
    // 获取 UIContext 实例
    this.uiContext = this.getUIContext();
    if (this.uiContext) {
      // 启用自定义键盘接续功能
      this.uiContext.setCustomKeyboardContinueFeature(true);
      console.info('Custom keyboard continue feature enabled.');
    }
  }

  // 自定义键盘布局:一个简单的数字键盘
  @Builder
  customKeyboardBuilder() {
    Column() {
      Row() {
        this.createButton('1')
        this.createButton('2')
        this.createButton('3')
      }
      Row() {
        this.createButton('4')
        this.createButton('5')
        this.createButton('6')
      }
      Row() {
        this.createButton('7')
        this.createButton('8')
        this.createButton('9')
      }
      Row() {
        this.createButton('0')
        this.createButton('清除')
      }
    }
    .width('100%')
    .height(240)
    .backgroundColor(Color.Gray)
    .padding(10)
  }

  @Builder
  createButton(label: string) {
    Button(label)
      .width(60)
      .height(60)
      .margin(5)
      .onClick(() => {
        // 此处仅为演示,实际键盘需要与输入框进行数据绑定
        console.info(`Key pressed: ${label}`);
      })
  }

  build() {
    Column({ space: 30 }) {
      Text('自定义键盘接续示例')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)

      TextInput({ placeholder: '输入框 1', text: this.inputValue1 })
        .width('90%')
        .height(56)
        .customKeyboard(this.customKeyboardBuilder())
        .onChange((value: string) => {
          this.inputValue1 = value;
        })

      TextInput({ placeholder: '输入框 2', text: this.inputValue2 })
        .width('90%')
        .height(56)
        .customKeyboard(this.customKeyboardBuilder())
        .onChange((value: string) => {
          this.inputValue2 = value;
        })

      Text('提示:在两个输入框之间切换焦点,观察键盘是否保持展开')
        .fontSize(14)
        .fontColor(Color.Gray)
        .textAlign(TextAlign.Center)
        .width('90%')
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .backgroundColor(Color.White)
  }
}

4.2 -> 进阶用法:动态控制接续开关

在某些场景下,开发者可能需要根据业务逻辑动态开启或关闭接续功能。以下示例展示了如何通过按钮切换接续状态:

// DynamicContinueExample.ets
import { UIContext } from '@kit.ArkUI';

@Entry
@Component
struct DynamicContinueExample {
  @State inputValue: string = '';
  @State isContinueEnabled: boolean = true;
  private uiContext: UIContext | undefined = undefined;

  aboutToAppear() {
    this.uiContext = this.getUIContext();
    this.updateContinueFeature();
  }

  private updateContinueFeature() {
    if (this.uiContext) {
      this.uiContext.setCustomKeyboardContinueFeature(this.isContinueEnabled);
      console.info(`Continue feature set to: ${this.isContinueEnabled}`);
    }
  }

  @Builder
  customKeyboardBuilder() {
    Column() {
      Row() {
        this.createKey('A')
        this.createKey('B')
        this.createKey('C')
      }
      Row() {
        this.createKey('D')
        this.createKey('E')
        this.createKey('F')
      }
      Row() {
        this.createKey('空格')
        this.createKey('删除')
      }
    }
    .width('100%')
    .height(200)
    .backgroundColor(Color.Blue)
    .padding(10)
  }

  @Builder
  createKey(label: string) {
    Button(label)
      .width(70)
      .height(50)
      .margin(5)
      .onClick(() => {
        // 键盘按键逻辑
      })
  }

  build() {
    Column({ space: 20 }) {
      Text('动态控制键盘接续')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)

      Row({ space: 20 }) {
        Text(`接续状态: ${this.isContinueEnabled ? '已开启' : '已关闭'}`)
          .fontSize(16)

        Button(this.isContinueEnabled ? '关闭接续' : '开启接续')
          .onClick(() => {
            this.isContinueEnabled = !this.isContinueEnabled;
            this.updateContinueFeature();
          })
      }

      TextInput({ placeholder: '输入框 1', text: this.inputValue })
        .width('90%')
        .height(56)
        .customKeyboard(this.customKeyboardBuilder())

      TextInput({ placeholder: '输入框 2', text: this.inputValue })
        .width('90%')
        .height(56)
        .customKeyboard(this.customKeyboardBuilder())

      Text('提示:点击按钮切换接续功能,在两个输入框间切换焦点观察效果')
        .fontSize(14)
        .fontColor(Color.Gray)
        .textAlign(TextAlign.Center)
        .width('90%')
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .padding(20)
  }
}

4.3 -> 在 Ability 层面全局启用

如果希望在应用全局范围内启用自定义键盘接续,可以在 EntryAbilityonWindowStageCreate 生命周期中设置:

// EntryAbility.ets
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { UIContext } from '@kit.ArkUI';

export default class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage): void {
    // 获取 UIContext 并启用接续
    const uiContext = windowStage.getMainWindowSync().getUIContext();
    uiContext.setCustomKeyboardContinueFeature(true);

    windowStage.loadContent('pages/Index', (err, data) => {
      if (err.code) {
        return;
      }
    });
  }
}

5 -> 注意事项与最佳实践

5.1 -> 接口调用时机

setCustomKeyboardContinueFeature 的调用时机至关重要。建议在页面或 Ability 的 aboutToAppearonWindowStageCreate 生命周期中尽早调用,确保在用户与输入框交互之前接续功能已经生效。

如果在输入框已经获得焦点之后才调用该接口,可能无法立即生效,需要重新触发焦点切换才能应用新的设置。

5.2 -> 作用范围

该接口作用于当前 UIContext 实例所对应的 UI 上下文范围。在大多数场景下,一个页面或 Ability 对应一个 UIContext,因此在该上下文中设置接续功能后,该页面内所有绑定了自定义键盘的输入组件都将受此设置影响。

需要注意的是,通过不同方式获取的 UIContext 实例(如 this.getUIContext()window.getUIContext())指向的是同一个 UI 上下文,因此设置效果是一致的。

5.3 -> 与系统键盘的交互

setCustomKeyboardContinueFeature 仅控制自定义键盘之间切换时的接续行为。当用户从自定义键盘切换到系统键盘(即某个输入框未绑定 customKeyboard 或绑定了 undefined)时,键盘仍然会正常收起。该接口不影响系统键盘的行为。

5.4 -> 与键盘避让模式的配合

在启用键盘接续时,建议同时关注 setKeyboardAvoidMode 的设置。如果页面布局在键盘弹出时会进行避让(如 RESIZE 模式),键盘保持展开状态时页面的布局调整应该保持稳定,避免在输入框切换时出现布局闪烁。

5.5 -> 多实例场景

在复杂的应用场景中,可能存在多个 UIContext 实例(如多窗口或多 Ability 场景)。此时需要分别为每个 UIContext 实例调用 setCustomKeyboardContinueFeature 来独立控制各上下文中的键盘接续行为。

5.6 -> 版本兼容性

该接口从 API version 23(鸿蒙 6.0)开始支持。在开发时需要注意:

  • 使用该接口的应用需要将 compileSdkVersion 配置为 23 或以上。
  • 在低版本设备上运行时,建议进行版本判断,避免调用不存在的 API 导致应用崩溃。
// 版本兼容性检查示例
if (deviceInfo.apiVersion >= 23) {
  this.getUIContext().setCustomKeyboardContinueFeature(true);
}

6 -> 总结

setCustomKeyboardContinueFeature 是鸿蒙 6.0 在输入体验优化方面的一项精准而实用的能力增强。它解决了自定义键盘在多输入框场景下「频繁收起弹出」的体验痛点,使自定义键盘的交互流畅度向系统键盘看齐。

从技术实现角度看,该接口通过 UIContext 这一 UI 上下文管理类提供了统一的行为控制入口,调用方式简洁明了,与现有的自定义键盘体系(customKeyboard 属性)无缝衔接。从 API version 23 开始支持在 attributeModifier 中调用,进一步拓展了其在状态驱动 UI 场景下的应用空间。

对于追求高品质输入体验的应用开发者而言,合理运用这一接口,配合自定义键盘的布局设计与输入逻辑,能够在表单填写、安全验证、富文本编辑等场景中显著提升用户的操作效率与满意度。建议开发者在涉及多输入框的自定义键盘场景中,将启用接续功能作为标配实践,为用户提供更加连贯、流畅的输入体验。


感谢各位大佬支持!!!

互三啦!!!
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐