自定义键盘的实现包括以下几个步骤:

  • 自定义键盘布局实现
  • 输入控件绑定自定义键盘布局
  • 自定义键盘输入控制
  • 自定义键盘光标控制
  • 自定义键盘弹出与收起

自定义键盘布局实现

自定义键盘的布局以自定义组件的方式呈现,根据具体业务场景由开发者实现。自定义键盘的高度通过自定义组件根节点的height属性设置,宽度不可设置,默认为屏幕宽度。

@Component
export struct CustomKeyboard {
  // ...
  build() {
    Column() {
      // ...
    }
    // ...
    .height(this.getKeyboardHeightVp())
    // ...
  }
}

代码逻辑走读:

  1. 组件定义:使用@Component装饰器定义了一个名为CustomKeyboard的组件,这表明它是一个可重用的UI组件。
  2. 方法定义:在CustomKeyboard结构体中定义了一个build方法,这个方法是组件的核心,用于构建和渲染UI。
  3. 布局使用:在build方法中,使用了Column布局来组织键盘的各个部分。Column是一个垂直布局,适合用于按键排列。
  4. 高度设置:通过调用this.getKeyboardHeightVp()方法,设置了键盘的高度。这个方法可能返回一个动态计算的高度值,以适应不同的设备或用户设置。
  5. 注释和省略:代码中包含了一些被省略的部分(// ...),这表明在实际应用中,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'))
  }
}

代码逻辑走读:

  1. 组件定义与依赖注入
    • 使用@Component装饰器定义了一个名为NumberKeyboard的组件。
    • 使用@Consume装饰器从父组件中注入inputTextkeyboardController,分别用于存储输入的文本和控制键盘行为。
  2. 布局选项定义
    • 定义了一个layoutOptions对象,用于配置GridLayout的布局。
    • regularSizeirregularIndexes用于指定网格项的常规大小和不规则项的索引。
    • onGetIrregularSizeByIndex是一个回调函数,根据索引返回按钮的宽度和高度。
  3. 构建键盘布局
    • 使用Grid组件创建一个网格布局,传入undefinedlayoutOptions
    • 使用ForEach循环遍历numberKeyboardData数组,为每个数据项创建一个GridItem
    • 在每个GridItem中,创建一个Button组件,按钮的文本和样式由数据项的textbackgroundColor属性决定。
  4. 按钮点击事件处理
    • 每个按钮的点击事件会调用onClick回调函数。
    • 在点击事件中,调用keyboardControlleronInput方法,将按钮的文本传递给inputText,从而更新输入的文本。
  5. 样式和布局配置
    • 使用columnsTemplaterowsGapcolumnsGap等方法配置网格的列布局和间距。

输入控件绑定自定义键盘布局

输入控件(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()
  }
}

代码逻辑走读:

  1. 构建函数 build()
    • 创建一个 Column布局容器,用于垂直排列子组件。
    • Column中添加一个 TextInput组件,该组件用于接收用户输入。
    • TextInput组件的属性包括:
      • placeholder:输入提示文本,显示在输入框为空时。
      • text:绑定到 this.inputText,用于存储用户输入的文本。
      • controller:绑定到 this.textInputController,用于控制输入框的行为。
    • 使用注释 // ...表示代码片段中可能存在其他未显示的逻辑。
    • 根据this.isCustomKeyboardAttach的值动态绑定自定义键盘:
      • 如果 this.isCustomKeyboardAttach为真,则调用 this.customKeyboard()方法绑定自定义键盘。
      • 如果为假,则不绑定自定义键盘。
  2. 自定义键盘构建器 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();
    }
  }

  // ...
}

代码逻辑走读:

  1. 组件定义:使用 @Component装饰器定义了一个名为 TextInputComponent的组件。
  2. 属性声明:声明了一个名为 isKeyboardShown的属性,类型为布尔值,并使用 @Link@Watch('onChangeKeyboard')装饰器,这意味着当 isKeyboardShown值改变时,会调用 onChangeKeyboard方法。
  3. 方法定义:定义了一个名为onChangeKeyboard的方法,用于处理键盘显示状态的变化。
    • onChangeKeyboard方法中,首先检查 isKeyboardShown是否为 false
    • 如果为 false,则调用 textInputControllerstopEditing方法,停止文本输入的编辑。
  4. 其他逻辑:代码中可能还包含其他逻辑,例如文本输入的控制器初始化和文本输入的其他功能,但这些逻辑在提供的代码片段中没有详细展示。

输入组件内有两个事件:

onFocus代表获得焦点,用户点击输入组件的时候,输入组件会获得焦点从而弹出键盘,此时设定isKeyboardShown为true,表示弹起;

onBlur代表失去焦点,当输入组件失去焦点,会被调用, 此时设为isKeyboardShown为false,表示收起;

.onBlur(() => {
  this.isKeyboardShown = false;
  // ...
})
.onFocus(() => {
  this.isKeyboardShown = true;
  // ...
})

代码逻辑走读:

  1. 事件监听器定义:代码定义了两个事件监听器,分别是 .onBlur().onFocus(),它们分别绑定了输入框失去焦点和获得焦点的事件处理函数。
  2. 焦点事件处理:
    • 当输入框失去焦点时,.onBlur()触发,执行箭头函数内的代码。
    • 在箭头函数中,将组件的状态变量 isKeyboardShown设置为 false,表示键盘不再显示。
  3. 聚焦事件处理:
    • 当输入框获得焦点时,.onFocus()触发,执行箭头函数内的代码。
    • 在箭头函数中,将组件的状态变量 isKeyboardShown设置为 true,表示键盘正在显示。
  4. 注释说明:代码中包含注释 // ...,可能是为了说明在实际应用中可能会有更多的逻辑处理,但具体内容未提供。

页面内的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'))
  }
}

代码逻辑走读:

  1. 组件定义与状态初始化
    • 使用@Entry@Component装饰器定义了一个名为MainPage的组件。
    • 初始化了一个状态变量isKeyboardShown,用于跟踪键盘是否显示(初始值为false)。
  2. 页面结构构建
    • 使用Navigation组件创建一个导航容器。
    • Navigation内部,使用Column组件垂直排列子元素。
  3. 事件处理
    • Navigation组件添加了一个点击事件处理函数。
    • 在点击事件中,检查isKeyboardShown的值:如果为true,则将其设置为false,表示隐藏键盘。
  4. 导航模式与标题设置
    • 设置导航模式为NavigationMode.Stack
    • 设置标题模式为NavigationTitleMode.Full
      Navigation内部,使用Column`组件垂直排列子元素。
Logo

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

更多推荐