当前位置:   article > 正文

鸿蒙next角落里的知识:“输入法编辑”—IME Kit_harmonyos imekit 依赖

harmonyos imekit 依赖

 Kit使用场景

IME Kit提供输入法框架和输入法服务两类API。用于实现输入法应用,也可以用于实现自绘编辑框以及实现对输入法应用的控制。

框架原理

功能特点

  • 输入法应用:

    支持创建固定态、悬浮态和状态栏三种类型的Panel,可支持开发一个输入法应用同时部署在手机、平板多设备中。

  • 自定义编辑框:

    支持开发者自定义编辑框,实现绑定输入法应用,并实现输入法应用的文输入、删除、选中、光标移动等操作。

能力范围

  • 提供输入法服务相关API,用于输入法应用,包括:创建软键盘窗口、插入/删除字符、选中文本、监听物理键盘按键事件等;

  • 提供输入法框架相关API,可用于自绘编辑框,包括绑定输入法,实现输入、删除、选中、光标移动等。

  • 提供系统应用管理输入法应用能力,实现对输入法应用的控制,包括显示/隐藏输入法软键盘、切换输入法、获取所有输入法列表。

与相关Kit的关系

ArkUI: IME Kit在输入法软键盘和自绘编辑框时使用ArkUI提供的部分组件、事件、动效、状态管理等能力,例如Text、Button组件,onClick点击事件。

实现一个输入法应用

  • onCreate()

    服务被首次创建时触发该回调,开发者可以在此进行一些初始化的操作,例如注册公共事件监听等。

    说明

    如果服务已创建,再次启动该InputMethodExtensionAbility不会触发onCreate()回调。

  • onDestroy()

    当不再使用服务且准备将该实例销毁时,触发该回调。开发者可以在该回调中清理资源,如注销监听等。

开发步骤

开发者在实现一个输入法应用时,需要在DevEco Studio工程中新建一个InputMethodExtensionAbility,具体步骤如下:

  1. 在工程Module对应的ets目录下,右键选择“New > Directory”,新建一个目录,并命名为InputMethodExtensionAbility。

  2. 在InputMethodExtensionAbility目录下,右键选择“New > File”,新建四个文件,分别为KeyboardController.ts、InputMethodService.ts、Index.ets以及KeyboardKeyData.ts。目录如下:

  1. /src/main/
  2. ├── ets/InputMethodExtensionAbility
  3. │ └──model/KeyboardController.ts # 显示键盘
  4. │ └──InputMethodService.ts # 自定义类继承InputMethodExtensionAbility并加上需要的生命周期回调
  5. │ └──pages
  6. │ └── Index.ets # 绘制键盘,添加输入删除功能
  7. │ └── KeyboardKeyData.ts # 键盘属性定义
  8. ├── resources/base/profile/main_pages.json

文件介绍

  1. InputMethodService.ts文件。

    在InputMethodService.ts文件中,增加导入InputMethodExtensionAbility的依赖包,自定义类继承InputMethodExtensionAbility并加上需要的生命周期回调。

    1. import { Want } from '@kit.AbilityKit';
    2. import keyboardController from './model/KeyboardController';
    3. import { InputMethodExtensionAbility } from '@kit.IMEKit';
    4. export default class InputDemoService extends InputMethodExtensionAbility {
    5. onCreate(want: Want): void {
    6. keyboardController.onCreate(this.context); // 初始化窗口并注册对输入法框架的事件监听
    7. }
    8. onDestroy(): void {
    9. console.log("onDestroy.");
    10. keyboardController.onDestroy(); // 销毁窗口并去注册事件监听
    11. }
    12. }
  2. KeyboardController.ts文件。

    1. import { common } from '@kit.AbilityKit';
    2. import { display } from '@kit.ArkUI';
    3. import { inputMethodEngine, InputMethodExtensionContext } from '@kit.IMEKit';
    4. // 调用输入法框架的getInputMethodAbility方法获取实例,并由此实例调用输入法框架功能接口
    5. const inputMethodAbility: inputMethodEngine.InputMethodAbility = inputMethodEngine.getInputMethodAbility();
    6. export class KeyboardController {
    7. private mContext: InputMethodExtensionContext | undefined = undefined; // 保存InputMethodExtensionAbility中的context属性
    8. private panel: inputMethodEngine.Panel | undefined = undefined;
    9. private textInputClient: inputMethodEngine.InputClient | undefined = undefined;
    10. private keyboardController: inputMethodEngine.KeyboardController | undefined = undefined;
    11. constructor() {
    12. }
    13. public onCreate(context: InputMethodExtensionContext): void
    14. {
    15. this.mContext = context;
    16. this.initWindow(); // 初始化窗口
    17. this.registerListener(); // 注册对输入法框架的事件监听
    18. }
    19. public onDestroy(): void // 应用生命周期销毁
    20. {
    21. this.unRegisterListener(); // 去注册事件监听
    22. if(this.panel) { // 销毁窗口
    23. this.panel.hide();
    24. inputMethodAbility.destroyPanel(this.panel);
    25. }
    26. if(this.mContext) {
    27. this.mContext.destroy();
    28. }
    29. }
    30. public insertText(text: string): void {
    31. if(this.textInputClient) {
    32. this.textInputClient.insertText(text);
    33. }
    34. }
    35. public deleteForward(length: number): void {
    36. if(this.textInputClient) {
    37. this.textInputClient.deleteForward(length);
    38. }
    39. }
    40. private initWindow(): void // 初始化窗口
    41. {
    42. if(this.mContext === undefined) {
    43. return;
    44. }
    45. let dis = display.getDefaultDisplaySync();
    46. let dWidth = dis.width;
    47. let dHeight = dis.height;
    48. let keyHeightRate = 0.47;
    49. let keyHeight = dHeight * keyHeightRate;
    50. let nonBarPosition = dHeight - keyHeight;
    51. let panelInfo: inputMethodEngine.PanelInfo = {
    52. type: inputMethodEngine.PanelType.SOFT_KEYBOARD,
    53. flag: inputMethodEngine.PanelFlag.FLG_FIXED
    54. };
    55. inputMethodAbility.createPanel(this.mContext, panelInfo).then(async (inputPanel: inputMethodEngine.Panel) => {
    56. this.panel = inputPanel;
    57. if(this.panel) {
    58. await this.panel.resize(dWidth, keyHeight);
    59. await this.panel.moveTo(0, nonBarPosition);
    60. await this.panel.setUiContent('inputmethodextability/pages/Index');
    61. }
    62. });
    63. }
    64. private registerListener(): void
    65. {
    66. this.registerInputListener(); // 注册对输入法框架服务的监听
    67. // 注册隐藏键盘事件监听等
    68. }
    69. private registerInputListener(): void { // 注册对输入法框架服务的开启及停止事件监听
    70. inputMethodAbility.on('inputStart', (kbController, textInputClient) => {
    71. this.textInputClient = textInputClient; // 此为输入法客户端实例,由此调用输入法框架提供给输入法应用的功能接口
    72. this.keyboardController = kbController;
    73. })
    74. inputMethodAbility.on('inputStop', () => {
    75. this.onDestroy(); // 销毁KeyboardController
    76. });
    77. }
    78. private unRegisterListener(): void
    79. {
    80. inputMethodAbility.off('inputStart');
    81. inputMethodAbility.off('inputStop', () => {});
    82. }
    83. }
    84. const keyboardController = new KeyboardController();
    85. export default keyboardController;
  3. KeyboardKeyData.ts文件。

    定义软键盘的按键显示内容。

    1. export interface sourceListType {
    2. content: string,
    3. }
    4. export let numberSourceListData: sourceListType[] = [
    5. {
    6. content: '1'
    7. },
    8. {
    9. content: '2'
    10. },
    11. {
    12. content: '3'
    13. },
    14. {
    15. content: '4'
    16. },
    17. {
    18. content: '5'
    19. },
    20. {
    21. content: '6'
    22. },
    23. {
    24. content: '7'
    25. },
    26. {
    27. content: '8'
    28. },
    29. {
    30. content: '9'
    31. },
    32. {
    33. content: '0'
    34. }
    35. ]
  4. Index.ets文件。

    主要描绘了具体按键功能。如按下数字键,就会将数字内容在输入框中打印出来,按下删除键,就会将内容删除。

    同时在resources/base/profile/main_pages.json文件的src字段中添加此文件路径。

    1. import { numberSourceListData, sourceListType } from './keyboardKeyData';
    2. import keyboardController from '../InputMethodExtensionAbility/model/KeyboardController';
    3. @Component
    4. struct keyItem {
    5. private keyValue: sourceListType = numberSourceListData[0];
    6. @State keyBgc: string = "#fff"
    7. @State keyFontColor: string = "#000"
    8. build() {
    9. Column() {
    10. Flex({ direction: FlexDirection.Column,
    11. alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
    12. Text(this.keyValue.content).fontSize(20).fontColor(this.keyFontColor)
    13. }
    14. }
    15. .backgroundColor(this.keyBgc)
    16. .borderRadius(6)
    17. .width("8%")
    18. .height("65%")
    19. .onClick(() => {
    20. keyboardController.insertText(this.keyValue.content);
    21. })
    22. }
    23. }
    24. // 删除组件
    25. @Component
    26. export struct deleteItem {
    27. @State keyBgc: string = "#fff"
    28. @State keyFontColor: string = "#000"
    29. build() {
    30. Column() {
    31. Flex({ direction: FlexDirection.Column,
    32. alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
    33. Text("删除").fontSize(20).fontColor(this.keyFontColor)
    34. }
    35. }
    36. .backgroundColor(this.keyBgc)
    37. .width("13%")
    38. .borderRadius(6)
    39. .onClick(() => {
    40. keyboardController.deleteForward(1);
    41. })
    42. }
    43. }
    44. // 数字键盘
    45. @Component
    46. struct numberMenu {
    47. private numberList: sourceListType[] = numberSourceListData;
    48. build() {
    49. Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceEvenly }) {
    50. Flex({ justifyContent: FlexAlign.SpaceBetween }) {
    51. ForEach(this.numberList, (item: sourceListType) => { // 数字键盘第一行
    52. keyItem({ keyValue: item })
    53. }, (item: sourceListType) => item.content);
    54. }
    55. .padding({ top: "2%" })
    56. .width("96%")
    57. .height("25%")
    58. Flex({ justifyContent: FlexAlign.SpaceBetween }) {
    59. deleteItem()
    60. }
    61. .width("96%")
    62. .height("25%")
    63. }
    64. }
    65. }
    66. @Entry
    67. @Component
    68. struct Index {
    69. private numberList: sourceListType[] = numberSourceListData
    70. build() {
    71. Stack() {
    72. Flex({
    73. direction: FlexDirection.Column,
    74. alignItems: ItemAlign.Center,
    75. justifyContent: FlexAlign.End
    76. }) {
    77. Flex({
    78. direction: FlexDirection.Column,
    79. alignItems: ItemAlign.Center,
    80. justifyContent: FlexAlign.SpaceBetween
    81. }) {
    82. numberMenu({
    83. numberList: this.numberList
    84. })
    85. }
    86. .align(Alignment.End)
    87. .width("100%")
    88. .height("75%")
    89. }
    90. .height("100%").align(Alignment.End).backgroundColor("#cdd0d7")
    91. }
    92. .position({ x: 0, y: 0 }).zIndex(99999)
    93. }
    94. }
  5. 在工程Module对应的module.json5配置文件module.json5配置文件module.json5配置文件中注册InputMethodExtensionAbility,type标签需要设置为“inputMethod”,srcEntry标签表示当前InputMethodExtensionAbility组件所对应的代码路径。

    1. {
    2. "module": {
    3. ...
    4. "extensionAbilities": [
    5. {
    6. "description": "inputMethod",
    7. "icon": "$media:icon",
    8. "name": "InputMethodExtAbility",
    9. "srcEntry": "./ets/InputMethodExtensionAbility/InputMethodService.ts",
    10. "type": "inputMethod",
    11. "exported": true,
    12. }
    13. ]
    14. }
    15. }

验证方法

  1. 在应用中通过接口拉起输入法切换列表弹窗。
  1. import { inputMethod } from '@kit.IMEKit';
  2. import { BusinessError } from '@kit.BasicServicesKit';
  3. let inputMethodSetting = inputMethod.getSetting();
  4. try {
  5. inputMethodSetting.showOptionalInputMethods((err: BusinessError, data: boolean) => {
  6. if (err) {
  7. console.error(`Failed to showOptionalInputMethods: ${JSON.stringify(err)}`);
  8. return;
  9. }
  10. console.log('Succeeded in showing optionalInputMethods.');
  11. });
  12. } catch (err) {
  13. console.error(`Failed to showOptionalInputMethods: ${JSON.stringify(err)}`);
  14. }
  1. 在弹窗上显示的输入法应用列表中,选择并点击demo应用,将demo应用切换为当前输入法。

  2. 点击任意编辑框,即可拉起输入法demo。

约束与限制

为了降低InputMethodExtensionAbility能力被三方应用滥用的风险,在InputMethodExtensionAbility中限制调用以下模块中的接口。

  • 若导入被限制的模块,在编译时不报错,在运行时会返回错误的值,即undefined,导致不生效。
  • 当前未禁止对音频管理模块@ohos.multimedia.audio (音频管理)@ohos.multimedia.audio (音频管理)@ohos.multimedia.audio (音频管理)的访问,但要求开发者应遵循以下约定:
    • 不得因用户未授予录音权限而禁止用户使用输入法应用的非语音输入法功能;
    • 仅允许InputMethodExtensionAbility处于前台时开展与录音相关的业务。如仅允许软键盘在前台且用户主动操作语音输入法时,才进行录音;应用切换到后台时,应主动停止录音;
    • 系统会逐步增加对违反以上约定的行为进行管控和识别,因此未遵守此约定可能会造成业务功能异常。
  • 严格遵从基础访问模式的功能约束。在此模式下,开发者应仅提供基础打字功能,不应提供任何形式与网络交互相关的功能。系统会逐步增加基础访问模式的安全管控能力,包括但不限于:以独立进程和沙箱的方式运行Extension进程;禁止Extension进程创建子进程;进程间通信与网络访问等。因此未遵从此约定可能会导致功能异常。

自绘编辑框

开发步骤

  1. 开发者在实现一个自绘编辑框控件时,需要在在DevEco Studio工程中新建一个ets文件,命名为自定义控件的名称,本示例中命名为CustomInput,在文件中定义一个自定义控件,并从@kit.IMEKit中导入inputMethod。

    1. import { inputMethod } from '@kit.IMEKit';
    2. @Component
    3. export struct CustomInput {
    4. build() {
    5. }
    6. }
  2. 在控件中,使用Text组件作为自会编辑框的文本显示组件,使用状态变量inputText作为Text组件要显示的内容。

    1. import { inputMethod } from '@kit.IMEKit';
    2. @Component
    3. export struct CustomInput {
    4. @State inputText: string = ''; // inputText作为Text组件要显示的内容。
    5. build() {
    6. Text(this.inputText) // Text组件作为自会编辑框的文本显示组件。
    7. .fontSize(16)
    8. .width('100%')
    9. .lineHeight(40)
    10. .id('customInput')
    11. .height(45)
    12. .border({ color: '#554455', radius: 30, width: 1 })
    13. .maxLines(1)
    14. }
    15. }
  3. 在控件中获取inputMethodController实例,并在文本点击时调用controller示例的attach方法绑定和拉起软键盘,并注册监听输入法插入文本、删除等方法,本示例仅展示插入、删除。

    1. import { inputMethod } from '@kit.IMEKit';
    2. @Component
    3. export struct CustomInput {
    4. @State inputText: string = ''; // inputText作为Text组件要显示的内容。
    5. private inputController: inputMethod.InputMethodController = inputMethod.getController();
    6. build() {
    7. Text(this.inputText) // Text组件作为自会编辑框的文本显示组件。
    8. .fontSize(16)
    9. .width('100%')
    10. .lineHeight(40)
    11. .id('customInput')
    12. .height(45)
    13. .border({ color: '#554455', radius: 30, width: 1 })
    14. .maxLines(1)
    15. .onClick(()=>{
    16. this.attachAndListener(); // 点击控件
    17. })
    18. }
    19. async attachAndListener() { // 绑定和设置监听
    20. focusControl.requestFocus('CustomInput');
    21. await this.inputController.attach(true, {
    22. inputAttribute: {
    23. textInputType: inputMethod.TextInputType.TEXT,
    24. enterKeyType: inputMethod.EnterKeyType.SEARCH
    25. }
    26. });
    27. this.inputController.on('insertText', (text) => {
    28. this.inputText += text;
    29. })
    30. this.inputController.on('deleteLeft', (length) => {
    31. this.inputText = this.inputText.substring(0, this.inputText.length - length);
    32. })
    33. }
    34. }
  4. 在应用界面布局中引入该控件即可,此处假设使用界面为Index.ets和控件CustomInput.ets在同一目录下。

最后

有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)资料用来跟着学习是非常有必要的。 

点击领取→【纯血版鸿蒙全套最新学习资料】(安全链接,放心点击

这份鸿蒙(HarmonyOS NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、(南向驱动、嵌入式等)鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。

希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!


 鸿蒙(HarmonyOS NEXT)最新学习路线

有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。

获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

HarmonyOS Next 最新全套视频教程

 《鸿蒙 (OpenHarmony)开发基础到实战手册》

OpenHarmony北向、南向开发环境搭建

《鸿蒙开发基础》

  • ArkTS语言
  • 安装DevEco Studio
  • 运用你的第一个ArkTS应用
  • ArkUI声明式UI开发
  • .……

《鸿蒙开发进阶》

  • Stage模型入门
  • 网络管理
  • 数据管理
  • 电话服务
  • 分布式应用开发
  • 通知与窗口管理
  • 多媒体技术
  • 安全技能
  • 任务管理
  • WebGL
  • 国际化开发
  • 应用测试
  • DFX面向未来设计
  • 鸿蒙系统移植和裁剪定制
  • ……

《鸿蒙进阶实战》

  • ArkTS实践
  • UIAbility应用
  • 网络案例
  • ……

大厂面试必问面试题

鸿蒙南向开发技术

鸿蒙APP开发必备

鸿蒙生态应用开发白皮书V2.0PDF


请点击→纯血版全套鸿蒙HarmonyOS学习资料

总结
总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。 

                   

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Guff_9hys/article/detail/887883
推荐阅读
相关标签
  

闽ICP备14008679号