第一、定义
自定义键盘是一种简易的键盘替换系统默认键盘,允许用户根据实际业务场景和习惯偏好,调整键盘的布局和位置、添加额外的功能键,使输入更加便捷和舒适,从而提升整体的用户体验。同时自定义键盘也可以增强用户输入的安全性,避免敏感信息被截取或者泄露。
第二、项目需求
三、实现
3.1、界面的实现
CustomKeyboardView.ets
import { CustomKeyboardController } from './CustomKeyboardController';
@Component
export struct
CustomKeyboardView{
titles:Array<string>=["1","2","3","4","5","6","7","8","9","0","X","-"]
@Consume inputText: string;
@Consume customKeyboardController: CustomKeyboardController;
build() {
Column(){
Flex({direction:FlexDirection.Row,justifyContent:FlexAlign.End}){
TextInput({text:this.inputText}).flexGrow(1).backgroundColor($r('app.color.white')).borderWidth($r('sys.float.border_small')).borderColor($r('app.color.black')).height(40).borderRadius(15).margin({top:5,right:10,bottom:5}).fontColor($r('app.color.black'))
Text($r('app.string.keyboardButton_delete')).backgroundColor($r('app.color.white')).borderWidth($r('sys.float.border_small')).borderColor($r('app.color.black')).height(40).borderRadius(10).margin({top:5,right:10,bottom:5}).width(100).textAlign(TextAlign.Center).onClick(()=>{
this.inputText=this.customKeyboardController.onInput($r('app.string.keyboardButton_delete'))
})
}.width('100%').height(40)
Grid(){
ForEach(this.titles,(title:string)=>{
GridItem(){
Text(title).backgroundColor($r('app.color.white')).borderWidth($r('sys.float.border_small')).borderColor($r('app.color.black')).width("100%").height(50).borderRadius(10).textAlign(TextAlign.Center).fontWeight(FontWeight.Bold).onClick(()=>{
if (title) {
this.inputText=this.customKeyboardController.onInput(title)
}
})
}
})
}.rowsTemplate('1fr 1fr 1fr 1fr').columnsTemplate('1fr 1fr 1fr').rowsGap(5).width('100%').height(240).columnsGap(10).margin({left:10,top:15,right:10})
}.width('100%').height(320).justifyContent(FlexAlign.Start).backgroundColor($r('app.color.grayF7')).padding({left:10,right:10})
}
}
3.2、界面引用
CustomKeyboardController.ets
import { emitter } from '@kit.BasicServicesKit';
import { Constants } from './Constants';
export class CustomKeyboardController {
textInputController?: TextInputController;
text: string = '';
leftCaretPos: number = 0;
rightCaretPos: number = 0;
targetCaretPos: number = 0;
keyBoardType: string = Constants.NUMBER_KEYBOARD;
isUpperCase: boolean = false;
onInput(value: string | Resource): string {
if (typeof value === 'string') {
this.text = this.text.substring(0, this.leftCaretPos) + value + this.text.substring(this.rightCaretPos);
this.targetCaretPos = this.leftCaretPos + value.length;
return this.text;
}
switch (value.id) {
case $r('app.string.keyboardButton_delete').id:
if (this.rightCaretPos === this.leftCaretPos && this.leftCaretPos > 0) {
this.leftCaretPos--;
}
this.text = this.text.substring(0, this.leftCaretPos) + this.text.substring(this.rightCaretPos);
this.targetCaretPos = this.leftCaretPos;
break;
}
return this.text;
}
onChange(value: string) {
this.text = value;
if (this.keyBoardType !== Constants.SYSTEM_KEYBOARD) {
this.textInputController?.caretPosition(this.targetCaretPos);
}
}
setCaretPosition(start: number, end: number) {
this.leftCaretPos = start;
this.rightCaretPos = end;
}
}
UseCustomKeyboard.ets
import { CustomKeyboardController } from './CustomKeyboardController';
import { CustomKeyboardView } from './CustomKeyboardView'
@Entry
@Component
struct UseCustomKeyboard {
@Provide customKeyboardController: CustomKeyboardController = new CustomKeyboardController()
@Provide inputText: string = '';
textInputController: TextInputController = new TextInputController();
aboutToAppear(): void {
this.customKeyboardController.textInputController = this.textInputController
}
build() {
Column() {
TextInput({ text: this.inputText, controller: this.textInputController })
.defaultFocus(false)
.customKeyboard(this.customKeyBoard)
}.width('100%').height('100%')
}
@Builder
customKeyBoard() {
CustomKeyboardView()
}
}
- customKeyboard
设置自定义键盘 - defaultFocus
默认不会获取光标,不会弹出键盘
3.3、运行效果
WC,怎么内容效果是反着的?继续改造
import { CustomKeyboardController } from './CustomKeyboardController';
import { CustomKeyboardView } from './CustomKeyboardView'
@Entry
@Component
struct UseCustomKeyboard {
@Provide customKeyboardController: CustomKeyboardController = new CustomKeyboardController()
@Provide inputText: string = '';
textInputController: TextInputController = new TextInputController();
aboutToAppear(): void {
this.customKeyboardController.textInputController = this.textInputController
}
build() {
Column() {
TextInput({ text: this.inputText, controller: this.textInputController })
.defaultFocus(false)
.customKeyboard(this.customKeyBoard)
.onTextSelectionChange((start: number, end: number) => {
this.customKeyboardController.setCaretPosition(start, end)
}).onChange((value) => {
this.inputText = value
this.customKeyboardController.onChange(value)
})
}.width('100%').height('100%')
}
@Builder
customKeyBoard() {
CustomKeyboardView()
}
}
- onTextSelectionChange
同步光标的位置 - onChange
同步内容变化
四、需求变更
键盘上面的输入框可以获取光标,并且可以调整光标的位置
基于上面的实现效果,无论怎么调整,键盘中的输入框始终无法获取焦点,估计是为了避免键盘的重叠显示,自定义的键盘中输入框就不能获取焦点,就只能另辟蹊径了。
五、开辟新思路
5.1、用弹窗实现
BottomBeyboardDialog.ets
import { CustomKeyboardController } from './CustomKeyboardController'
@CustomDialog
@Component
export struct BottomBeyboardDialog {
titles: Array<string> = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "X", "-"]
controller?: CustomDialogController
textInputController: TextInputController = new TextInputController()
customKeyboardController: CustomKeyboardController = new CustomKeyboardController()
@Link
enterContent?: string
aboutToAppear(): void {
this.customKeyboardController.textInputController = this.textInputController
}
build() {
Column() {
Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.End }) {
TextInput({ text: this.enterContent, controller: this.textInputController })
.flexGrow(1)
.defaultFocus(false)
.backgroundColor($r('app.color.white'))
.borderWidth($r('sys.float.border_small'))
.borderColor($r('app.color.black'))
.height(40)
.borderRadius(15)
.margin({ top: 5, right: 10, bottom: 5 })
.fontColor($r('app.color.black'))
.customKeyboard(this.emptyKeyBoard)
.onTextSelectionChange((selectionStart: number, selectionEnd: number) => {
this.customKeyboardController.setCaretPosition(selectionStart, selectionEnd)
})
.onChange((value) => {
this.enterContent = value
this.customKeyboardController.onChange(value)
})
Text($r('app.string.keyboardButton_delete'))
.backgroundColor($r('app.color.white'))
.borderWidth($r('sys.float.border_small'))
.borderColor($r('app.color.black'))
.height(40)
.borderRadius(10)
.margin({ top: 5, right: 10, bottom: 5 })
.width(100)
.textAlign(TextAlign.Center)
.onClick(() => {
this.enterContent = this.customKeyboardController.onInput($r('app.string.keyboardButton_delete'))
})
}.width('100%').height(40)
Grid() {
ForEach(this.titles, (title: string) => {
GridItem() {
Text(title)
.backgroundColor($r('app.color.white'))
.borderWidth($r('sys.float.border_small'))
.borderColor($r('app.color.black'))
.width("100%")
.height(50)
.borderRadius(10)
.textAlign(TextAlign.Center)
.fontWeight(FontWeight.Bold)
.onClick(() => {
this.enterContent = this.customKeyboardController.onInput(title)
})
}
})
}
.rowsTemplate('1fr 1fr 1fr 1fr')
.columnsTemplate('1fr 1fr 1fr')
.rowsGap(5)
.width('100%')
.height(240)
.columnsGap(10)
.margin({ left: 10, top: 15, right: 10 })
}
.width('100%')
.height(320)
.justifyContent(FlexAlign.Start)
.backgroundColor($r('app.color.grayF7'))
.padding({ left: 10, right: 10 })
}
@Builder
emptyKeyBoard() {
}
}
5.2、使用
UseCustomKeyboardWithDialog.ets
import { BottomBeyboardDialog } from './BottomBeyboardDialog';
import { CustomKeyboardController } from './CustomKeyboardController';
import { CustomKeyboardView } from './CustomKeyboardView';
@Entry
@Component
struct UseCustomKeyboardWithDialog {
@Provide customKeyboardController: CustomKeyboardController = new CustomKeyboardController()
@Provide inputText: string = '';
dialogController: CustomDialogController | null = new CustomDialogController({
builder: BottomBeyboardDialog({ enterContent: this.inputText }),
autoCancel: true,
alignment: DialogAlignment.Bottom,
customStyle: true,
maskColor: Color.Transparent
})
build() {
Column() {
TextInput({ text: this.inputText})
.focusable(false)
.onClick(()=>{
if (this.dialogController != null) {
this.dialogController.open()
}
})
}.width('100%').height('100%')
}
}
自定义键盘开发实践: https://developer.huawei.com/consumer/cn/doc/best-practices-V5/bpta-custom-keyboard-V5#section1840215515206
https://gitee.com/harmonyos_samples/CustomizeKeyboard