纯血鸿蒙NEXT-自定义键盘

第一、定义

自定义键盘是一种简易的键盘替换系统默认键盘,允许用户根据实际业务场景和习惯偏好,调整键盘的布局和位置、添加额外的功能键,使输入更加便捷和舒适,从而提升整体的用户体验。同时自定义键盘也可以增强用户输入的安全性,避免敏感信息被截取或者泄露。

第二、项目需求

在这里插入图片描述

三、实现

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值