HarmonyOS 键盘适配完整指南(下篇):自定义键盘实现
自定义键盘是一种简易的键盘替代系统默认键盘,允许用户根据实际业务场景和习惯偏好,调整键盘的布局和位置、添加额外的功能键,使输入更加便捷和舒适。同时自定义键盘也可以增强用户输入的安全性,避免敏感信息被截取或者泄露。自定义键盘的布局以自定义组件的方式呈现,根据具体业务场景由开发者实现。自定义键盘的高度通过自定义组件根节点的 height 属性设置,宽度不可设置,默认为屏幕宽度。
咱们这篇主要介绍自定义键盘的实现。上篇已介绍系统键盘基础、软键盘避让机制和常见问题解决方案。
自定义键盘实现
自定义键盘是一种简易的键盘替代系统默认键盘,允许用户根据实际业务场景和习惯偏好,调整键盘的布局和位置、添加额外的功能键,使输入更加便捷和舒适。
同时自定义键盘也可以增强用户输入的安全性,避免敏感信息被截取或者泄露。
自定义键盘布局实现
自定义键盘的布局以自定义组件的方式呈现,根据具体业务场景由开发者实现。
自定义键盘的高度通过自定义组件根节点的 height 属性设置,宽度不可设置,默认为屏幕宽度。
@Component
export struct CustomKeyboard {
build() {
Column() {
// ...
}
.height(this.getKeyboardHeightVp())
}
}
以 Grid 方式实现数字键盘布局示例:
@Component
export struct NumberKeyboard {
@Consume inputText: string;
@Consume keyboardController: KeyboardController;
layoutOptions: GridLayoutOptions = {
regularSize: [1, 1],
irregularIndexes: [14, 16],
onGetIrregularSizeByIndex: (index: number) => {
if (index === 14) {
return [2, 1];
}
return [1, 2];
}
};
build() {
Grid(undefined, this.layoutOptions) {
ForEach(numberKeyboardData, (item: Menu) => {
GridItem() {
Button(item.text, { type: ButtonType.Normal })
.fontColor(Color.Black)
.backgroundColor(item.backgroundColor)
.borderRadius(Constants.KEYBOARD_BUTTON_RADIUS)
.fontSize(Constants.KEYBOARD_BUTTON_FONTSIZE_18)
.padding(0)
.width(item.width)
.height(item.height)
.onClick(() => {
this.inputText = this.keyboardController.onInput(item.text);
})
}
}, (item: Menu) => JSON.stringify(item))
}
.columnsTemplate('1fr 1fr 1fr 1fr 1fr')
.rowsGap($r('app.float.number_keyboard_grid_gap'))
.columnsGap($r('app.float.number_keyboard_grid_gap'))
}
}
输入控件绑定自定义键盘
输入控件(TextArea、TextInput、RichEditor、Search)支持通过 customKeyboard 属性绑定自定义键盘布局。
绑定自定义键盘后,输入控件获取焦点时,不会拉起系统键盘,而是加载指定的自定义键盘。
build() {
Column() {
TextInput({
placeholder: 'Bind Custom Keyboard',
text: this.inputText,
controller: this.textInputController
})
.customKeyboard(this.isCustomKeyboardAttach ? this.customKeyboard() : null)
}
}
@Builder
customKeyboard() {
CustomKeyboard()
}
监听键盘弹出与收起
在输入组件内,使用@Link 和@Watch(‘onChangeKeyboard’) 修饰 isKeyboardShown。
当键盘状态变化后,会调用 onChangeKeyboard,此时要收起键盘,则执行和键盘控制器绑定的文字输入控制器的 stopEditing:
@Component
export struct TextInputComponent {
@Link @Watch('onChangeKeyboard') isKeyboardShown: boolean;
onChangeKeyboard() {
if (this.isKeyboardShown === false) {
this.textInputController.stopEditing();
}
}
}
输入组件内有两个事件:
- onFocus 代表获得焦点,用户点击输入组件的时候,输入组件会获得焦点从而弹出键盘,此时设定 isKeyboardShown 为 true
- onBlur 代表失去焦点,当输入组件失去焦点,会被调用,此时设为 isKeyboardShown 为 false
.onBlur(() => {
this.isKeyboardShown = false;
})
.onFocus(() => {
this.isKeyboardShown = true;
})
页面内的 isKeyboardShown 要和输入组件 TextInputComponent 建立双向绑定,用来监听 isKeyboardShown 变化,响应键盘的弹出与收起:
@Entry
@Component
struct MainPage {
@State isKeyboardShown: boolean = false;
build() {
Navigation() {
Column() {
// ...
}
.onClick(() => {
if (this.isKeyboardShown) {
this.isKeyboardShown = false;
}
})
.mode(NavigationMode.Stack)
.titleMode(NavigationTitleMode.Full)
}
}
}
横竖屏切换时设置键盘高度
在键盘组件 CustomKeyboard 引入方向检测与动态高度,在键盘组件内对应位置处理。
引入 @ohos.display,新增 @State isLandscape 保存当前方向。
在 aboutToAppear 注册监听器 display.on(‘change’),在 aboutToDisappear 注销监听器,方向变化时调用 updateOrientation(),通过 display.getDefaultDisplaySync() 判断 width > height 判定横屏:
@Component
export struct CustomKeyboard {
@State isLandscape: boolean = false;
aboutToAppear(): void {
this.updateOrientation();
try {
display.on('change', this.onDisplayChange);
} catch (e) {
// ignore
}
}
aboutToDisappear(): void {
try {
display.off('change', this.onDisplayChange);
} catch (e) {
// ignore
}
}
private updateOrientation() {
try {
const d = display.getDefaultDisplaySync();
this.isLandscape = d.width > d.height;
} catch (e) {
this.isLandscape = false;
}
}
}
重写 getKeyboardHeightVp(),判断设备为平板的时候,按照平板的比例给予,横屏 0.33,竖屏 0.22 的屏幕高度占比,手机的话固定为 0.36 的占比高度:
@Component
export struct CustomKeyboard {
private getKeyboardHeightVp(): number | Resource {
try {
const d = display.getDefaultDisplaySync();
const ui = this.getUIContext();
const screenHeightVp = ui.px2vp(d.height);
const shortSideVp = ui.px2vp(Math.min(d.width, d.height));
const isLargeScreen = shortSideVp >= 600;
const ratio = isLargeScreen
? (this.isLandscape ? 0.33 : 0.22)
: 0.36;
return Math.floor(screenHeightVp * ratio);
} catch (e) {
return $r('app.float.keyboard_total_height');
}
}
}
修改组件高度,将键盘组件的.height(…) 改为.height(this.getKeyboardHeightVp()) 以采用动态计算值。
自定义键盘输入控制
自定义键盘可以拦截手势事件,通过对状态变量的修改,实现文本的输入。
以英文键盘为例,监听 EnglishButton 的 onClick 事件,修改状态变量:
@Component
struct EnglishButton {
@Consume inputText: string;
build() {
Button({ type: ButtonType.Normal })
.onClick(() => {
this.inputText = this.keyboardController.onInput(this.getEnglishText(this.item));
})
}
}
通过对状态变量 inputText 的修改,实现文本输入:
@Component
export struct TextInputComponent {
@Provide inputText: string = '';
build() {
Column() {
TextInput({
placeholder: 'Bind Custom Keyboard',
text: this.inputText,
controller: this.textInputController
})
}
}
}
自定义键盘光标控制
通过监听 TextInput 的 onTextSelectionChange 生命周期,获取初始光标位置,文本输入后,调用 TextInputController 的 caretPosition 方法,设置最终光标位置。
获取光标位置:
TextInput({
placeholder: 'Bind Custom Keyboard',
text: this.inputText,
controller: this.textInputController
})
.onTextSelectionChange((start: number, end: number) => {
this.keyboardController.setCaretPosition(start, end);
})
设置光标位置:
onChange(value: string) {
this.text = value;
if (this.keyboardType !== 'System') {
this.textInputController?.caretPosition(this.targetCaretPos);
}
}
自定义键盘弹出与收起
通过对焦点进行控制,可以实现键盘的弹出和收起。
开发者也可以通过 TextInputController 的 stopEditing 方法控制键盘关闭,下面的自定义键盘示例中,点击确认按键关闭自定义键盘:
onInput(value: string | Resource): string {
switch (value.id) {
case $r('app.string.keyboardButton_finish').id:
this.textInputController?.stopEditing();
break;
}
return this.text;
}
自定义键盘和系统键盘的切换
当需要实现同一个输入框内可以切换自定义键盘和系统键盘时,可以通过如下方式实现:
Tab 栏点击"123"、"ABC"按钮,this.isCustomKeyboardAttach 为 true,TextInput 绑定自定义键盘;点击"中文"按钮,this.isCustomKeyboardAttach 为 false,切换系统键盘。
TextInput({
placeholder: 'Bind Custom Keyboard',
text: this.inputText,
controller: this.textInputController
})
.customKeyboard(this.isCustomKeyboardAttach ? this.customKeyboard() : null)
自定义键盘的布局避让
使用系统提供的自定义键盘避让功能
为了确保输入框不被自定义键盘挡住,系统默认提供了输入框避让自定义键盘的能力。
在 TextInput 组件的 customKeyboard 属性设置 supportAvoidance 为 true,开启系统提供的自定义键盘避让功能。
TextInput({
placeholder: 'Bind Custom Keyboard',
text: this.inputText,
controller: this.textInputController
})
.customKeyboard(this.customKeyboard(), { supportAvoidance: true })
系统默认的自定义键盘避让功能只能保证输入框不被遮挡,输入框下方的组件可能会被自定义键盘挡住。
开发者自己实现自定义键盘的避让功能
开发者需要监听自定义键盘根节点的 onAreaChange 生命周期,获取自定义键盘的高度,根据实际场景设置布局的避让。
监听自定义键盘布局的 onAreaChange 生命周期,通过 newValue.height 获取自定义键盘弹出时的高度,根据实际业务场景计算布局避让高度 avoidHeight:
@Component
export struct CustomKeyboard {
build() {
Column() {
// ...
}
.onAreaChange((oldValue: Area, newValue: Area) => {
this.customKeyboardHeight = Number(newValue.height);
let avoidHeight: number = (this.isCustomKeyboardAttach ? this.customKeyboardHeight : this.systemKeyboardHeight)
- this.bottomRectHeight;
this.keyboardController.changeAvoidHeight(avoidHeight);
})
}
}
通过 emitter 的方式,发送自定义键盘高度变化的通知:
changeAvoidHeight(value: number) {
let event: emitter.InnerEvent = {
eventId: Constants.AVOID_EVENT_ID
};
let eventData: emitter.EventData = {
data: {
'avoidHeight': value
}
};
emitter.emit(event, eventData);
}
接收到高度变化通知后,根据实际业务场景,设置页面的避让高度:
@Entry
@Component
struct MainPage {
@State bottomPadding: number = 210;
@State isKeyboardShown: boolean = false;
aboutToAppear(): void {
let event: emitter.InnerEvent = {
eventId: 1
}
emitter.on(event, (eventData: emitter.EventData) => {
if (eventData.data) {
let avoidHeight: number = eventData.data['avoidHeight'];
if (avoidHeight === 0) {
this.bottomPadding = 210;
} else {
this.bottomPadding = avoidHeight;
}
}
})
}
build() {
Navigation() {
Column() {
// ...
}
.padding({ bottom: this.bottomPadding })
}
.onClick(() => {
if (this.isKeyboardShown) {
this.isKeyboardShown = false;
}
})
.mode(NavigationMode.Stack)
.titleMode(NavigationTitleMode.Full)
}
}
自定义键盘实现防截屏
用户使用自定义键盘输入敏感信息时,可以设置禁止截屏,有效防止他人在未经许可的情况下获取用户的敏感信息,从而保护用户的隐私安全。
下篇总结
下篇介绍了自定义键盘的完整实现:
自定义键盘布局
- 自定义键盘布局实现(Grid 方式实现数字键盘)
- 输入控件绑定自定义键盘(customKeyboard 属性)
- 监听键盘弹出与收起(onFocus/onBlur/onChangeKeyboard)
- 横竖屏切换时设置键盘高度(动态计算高度)
输入控制
- 自定义键盘输入控制(拦截手势事件)
- 自定义键盘光标控制(onTextSelectionChange/caretPosition)
- 自定义键盘弹出与收起(stopEditing 方法)
- 自定义键盘和系统键盘的切换
布局避让
- 使用系统提供的自定义键盘避让功能(supportAvoidance)
- 开发者自己实现自定义键盘的避让功能(onAreaChange/emitter)
- 自定义键盘实现防截屏
全文总结
键盘适配是 HarmonyOS 开发中常见的需求,完整指南介绍了:
- 系统键盘的基础操作:弹出、收起、监听
- 软键盘避让机制:三种避让模式(上抬、压缩、不避让)
- 常见问题解决方案:布局错位、弹窗过度上抬等
- 自定义键盘实现:从布局到输入控制,从光标控制到布局避让
核心思想:了解系统的避让机制,根据实际场景选择合适的避让模式,必要时实现自定义键盘来满足特殊需求。
更多推荐


所有评论(0)