鸿蒙6.0应用开发——自定义键盘的实现
自定义键盘的布局以自定义组件的方式呈现,根据具体业务场景由开发者实现。自定义键盘的高度通过自定义组件根节点的height属性设置,宽度不可设置,默认为屏幕宽度。
自定义键盘的实现包括以下几个步骤:
- 自定义键盘布局实现
- 输入控件绑定自定义键盘布局
- 自定义键盘输入控制
- 自定义键盘光标控制
- 自定义键盘弹出与收起
自定义键盘布局实现
自定义键盘的布局以自定义组件的方式呈现,根据具体业务场景由开发者实现。自定义键盘的高度通过自定义组件根节点的height属性设置,宽度不可设置,默认为屏幕宽度。
@Component
export struct CustomKeyboard {
// ...
build() {
Column() {
// ...
}
// ...
.height(this.getKeyboardHeightVp())
// ...
}
}
代码逻辑走读:
- 组件定义:使用
@Component装饰器定义了一个名为CustomKeyboard的组件,这表明它是一个可重用的UI组件。 - 方法定义:在
CustomKeyboard结构体中定义了一个build方法,这个方法是组件的核心,用于构建和渲染UI。 - 布局使用:在
build方法中,使用了Column布局来组织键盘的各个部分。Column是一个垂直布局,适合用于按键排列。 - 高度设置:通过调用
this.getKeyboardHeightVp()方法,设置了键盘的高度。这个方法可能返回一个动态计算的高度值,以适应不同的设备或用户设置。 - 注释和省略:代码中包含了一些被省略的部分(
// ...),这表明在实际应用中,CustomKeyboard组件可能还有更多的属性和方法,或者在Column布局中还有更多的子组件。
以Grid方式实现数字键盘布局示例:
图1
@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'))
}
}
代码逻辑走读:
- 组件定义与依赖注入:
- 使用
@Component装饰器定义了一个名为NumberKeyboard的组件。 - 使用
@Consume装饰器从父组件中注入inputText和keyboardController,分别用于存储输入的文本和控制键盘行为。
- 使用
- 布局选项定义:
- 定义了一个
layoutOptions对象,用于配置GridLayout的布局。 regularSize和irregularIndexes用于指定网格项的常规大小和不规则项的索引。onGetIrregularSizeByIndex是一个回调函数,根据索引返回按钮的宽度和高度。
- 定义了一个
- 构建键盘布局:
- 使用
Grid组件创建一个网格布局,传入undefined和layoutOptions。 - 使用
ForEach循环遍历numberKeyboardData数组,为每个数据项创建一个GridItem。 - 在每个
GridItem中,创建一个Button组件,按钮的文本和样式由数据项的text和backgroundColor属性决定。
- 使用
- 按钮点击事件处理:
- 每个按钮的点击事件会调用
onClick回调函数。 - 在点击事件中,调用
keyboardController的onInput方法,将按钮的文本传递给inputText,从而更新输入的文本。
- 每个按钮的点击事件会调用
- 样式和布局配置:
- 使用
columnsTemplate和rowsGap、columnsGap等方法配置网格的列布局和间距。
- 使用
输入控件绑定自定义键盘布局
输入控件(TextArea、TextInput、RichEditor、Search)支持通过customKeyboard属性绑定自定义键盘布局。绑定自定义键盘后,输入控件获取焦点时,不会拉起系统键盘,而是加载指定的自定义键盘。本文后续以TextInput控件为例进行介绍。
图2
代码示例如下:
build() {
Column() {
TextInput({
placeholder: 'Bind Custom Keyboard',
text: this.inputText,
controller: this.textInputController
})
// ...
.customKeyboard(this.isCustomKeyboardAttach ? this.customKeyboard() : null)
// ...
}
}
@Builder
customKeyboard() {
CustomKeyboard()
}
}
代码逻辑走读:
- 构建函数
build():- 创建一个
Column布局容器,用于垂直排列子组件。 - 在
Column中添加一个TextInput组件,该组件用于接收用户输入。 - TextInput组件的属性包括:
placeholder:输入提示文本,显示在输入框为空时。text:绑定到this.inputText,用于存储用户输入的文本。controller:绑定到this.textInputController,用于控制输入框的行为。
- 使用注释
// ...表示代码片段中可能存在其他未显示的逻辑。 - 根据this.isCustomKeyboardAttach的值动态绑定自定义键盘:
- 如果
this.isCustomKeyboardAttach为真,则调用this.customKeyboard()方法绑定自定义键盘。 - 如果为假,则不绑定自定义键盘。
- 如果
- 创建一个
- 自定义键盘构建器
customKeyboard():- 使用
@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();
}
}
// ...
}
代码逻辑走读:
- 组件定义:使用
@Component装饰器定义了一个名为TextInputComponent的组件。 - 属性声明:声明了一个名为
isKeyboardShown的属性,类型为布尔值,并使用@Link和@Watch('onChangeKeyboard')装饰器,这意味着当isKeyboardShown值改变时,会调用onChangeKeyboard方法。 - 方法定义:定义了一个名为onChangeKeyboard的方法,用于处理键盘显示状态的变化。
- 在
onChangeKeyboard方法中,首先检查isKeyboardShown是否为false。 - 如果为
false,则调用textInputController的stopEditing方法,停止文本输入的编辑。
- 在
- 其他逻辑:代码中可能还包含其他逻辑,例如文本输入的控制器初始化和文本输入的其他功能,但这些逻辑在提供的代码片段中没有详细展示。
输入组件内有两个事件:
onFocus代表获得焦点,用户点击输入组件的时候,输入组件会获得焦点从而弹出键盘,此时设定isKeyboardShown为true,表示弹起;
onBlur代表失去焦点,当输入组件失去焦点,会被调用, 此时设为isKeyboardShown为false,表示收起;
.onBlur(() => {
this.isKeyboardShown = false;
// ...
})
.onFocus(() => {
this.isKeyboardShown = true;
// ...
})
代码逻辑走读:
- 事件监听器定义:代码定义了两个事件监听器,分别是
.onBlur()和.onFocus(),它们分别绑定了输入框失去焦点和获得焦点的事件处理函数。 - 焦点事件处理:
- 当输入框失去焦点时,
.onBlur()触发,执行箭头函数内的代码。 - 在箭头函数中,将组件的状态变量
isKeyboardShown设置为false,表示键盘不再显示。
- 当输入框失去焦点时,
- 聚焦事件处理:
- 当输入框获得焦点时,
.onFocus()触发,执行箭头函数内的代码。 - 在箭头函数中,将组件的状态变量
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)
.title($r('app.string.main_page_title'))
}
}
代码逻辑走读:
- 组件定义与状态初始化:
- 使用
@Entry和@Component装饰器定义了一个名为MainPage的组件。 - 初始化了一个状态变量
isKeyboardShown,用于跟踪键盘是否显示(初始值为false)。
- 使用
- 页面结构构建:
- 使用
Navigation组件创建一个导航容器。 - 在
Navigation内部,使用Column组件垂直排列子元素。
- 使用
- 事件处理:
- 为
Navigation组件添加了一个点击事件处理函数。 - 在点击事件中,检查
isKeyboardShown的值:如果为true,则将其设置为false,表示隐藏键盘。
- 为
- 导航模式与标题设置:
- 设置导航模式为
NavigationMode.Stack。 - 设置标题模式为
NavigationTitleMode.Full。
Navigation内部,使用Column`组件垂直排列子元素。
- 设置导航模式为
更多推荐

所有评论(0)