IME Kit ——打造专属输入法,让用户的输入独具风味(1) 原创

因为活着就一定行
发布于 2024-11-28 10:42
浏览
0收藏

搞懂IME:HarmonyOS输入法开发指南

Hey兄弟,今天咱们来聊聊在HarmonyOS里头怎么搞输入法(IME),这可是个技术活儿,但别担心,咱们一步步来。

IME是啥玩意儿?

IME,就是输入法框架,它能让应用和输入法应用之间能聊天,比如你在聊天框里敲字儿,它得把字儿显示出来,这就是IME的活儿。

怎么做?

在HarmonyOS里头,IME Kit提供了两套API,一套是输入法框架API,另一套是输入法服务API。用这些API,你可以自己搞个输入法应用,或者在你自己的应用里头用输入法。

8种应用场景

  1. 固定面板输入法:就像你手机屏幕上那个键盘,固定在那儿,你敲啥它显示啥。
  2. 悬浮面板输入法:这个能到处飘,你想在哪儿输入就飘到哪儿。
  3. 状态栏输入法:这个小不点儿,就在屏幕顶上,不占地儿。
  4. 多设备部署:你开发的输入法,手机、平板都能用。
  5. 自定义编辑框:你想让你的应用里的输入框与众不同,IME Kit帮你实现。
  6. 文字输入、删除:用户输入文字或者删除文字,IME Kit都能搞定。
  7. 光标移动、文本选择:用户想在哪儿编辑就在哪儿编辑,IME Kit提供这些操作的支持。
  8. 系统应用管理:系统级别的输入法管理,比如显示/隐藏输入法软键盘,切换输入法等。

代码实战

下面是根据文件内容整理的代码实例,咱们一块儿看看。

KeyboardKeyData.ts

// 定义键盘按键的数据结构
export interface KeyData {
  content: string;
}

// 数字键盘数据
export const numberKeys: KeyData[] = [
  { content: '1' }, { content: '2' }, { content: '3' },
  { content: '4' }, { content: '5' }, { content: '6' },
  { content: '7' }, { content: '8' }, { content: '9' },
  { content: '0' }, { content: '+' }, { content: '-' }
];

// 字母键盘第一行数据
export const letterKeysRow1: KeyData[] = [
  { content: 'Q' }, { content: 'W' }, { content: 'E' },
  { content: 'R' }, { content: 'T' }, { content: 'Y' },
  { content: 'U' }, { content: 'I' }, { content: 'O' },
  { content: 'P' }, { content: '[' }, { content: ']' }
];

// 字母键盘第二行数据
export const letterKeysRow2: KeyData[] = [
  { content: 'A' }, { content: 'S' }, { content: 'D' },
  { content: 'F' }, { content: 'G' }, { content: 'H' },
  { content: 'J' }, { content: 'K' }, { content: 'L' },
  { content: ';' }, { content: "'" }
];

// 字母键盘第三行数据
export const letterKeysRow3: KeyData[] = [
  { content: 'Z' }, { content: 'X' }, { content: 'C' },
  { content: 'V' }, { content: 'B' }, { content: 'N' },
  { content: 'M' }, { content: ',' }, { content: '.' },
  { content: '/' }, { content: '\\' }
];

KeyboardController.ts

import { display } from '@kit.ArkUI';
import { inputMethodEngine, InputMethodExtensionContext } from '@kit.IMEKit';

// 获取输入法框架的能力
const inputMethodAbility = inputMethodEngine.getInputMethodAbility();

export class KeyboardController {
  private context: InputMethodExtensionContext | undefined;
  private panel: inputMethodEngine.Panel | undefined;
  private textInputClient: inputMethodEngine.InputClient | undefined;

  constructor() {}

  // 创建输入法窗口和注册事件监听
  public onCreate(context: InputMethodExtensionContext): void {
    this.context = context;
    this.initWindow();
    this.registerListener();
  }

  // 销毁输入法窗口和注销事件监听
  public onDestroy(): void {
    this.unRegisterListener();
    if (this.panel) {
      this.panel.hide();
      inputMethodAbility.destroyPanel(this.panel);
    }
    if (this.context) {
      this.context.destroy();
    }
  }

  // 插入文本
  public insertText(text: string): void {
    if (this.textInputClient) {
      this.textInputClient.insertText(text);
    }
  }

  // 删除前向文本
  public deleteForward(length: number): void {
    if (this.textInputClient) {
      this.textInputClient.deleteForward(length);
    }
  }

  // 初始化窗口
  private initWindow(): void {
    if (!this.context) return;
    let displayInfo = display.getDefaultDisplaySync();
    let width = displayInfo.width;
    let height = displayInfo.height;
    let keyHeightRate = 0.47;
    let keyHeight = height * keyHeightRate;
    let nonBarPosition = height - keyHeight;
    let panelInfo: inputMethodEngine.PanelInfo = {
      type: inputMethodEngine.PanelType.SOFT_KEYBOARD,
      flag: inputMethodEngine.PanelFlag.FLG_FIXED
    };
    inputMethodAbility.createPanel(this.context, panelInfo).then((inputPanel: inputMethodEngine.Panel) => {
      this.panel = inputPanel;
      if (this.panel) {
        this.panel.resize(width, keyHeight);
        this.panel.moveTo(0, nonBarPosition);
        this.panel.setUiContent('InputMethodExtensionAbility/pages/Index');
      }
    });
  }

  // 注册事件监听
  private registerListener(): void {
    this.registerInputListener();
  }

  // 注册输入法框架服务的监听
  private registerInputListener(): void {
    inputMethodAbility.on('inputStart', (kbController, textInputClient) => {
      this.textInputClient = textInputClient;
    });
    inputMethodAbility.on('inputStop', () => {
      this.onDestroy();
    });
  }

  // 注销事件监听
  private unRegisterListener(): void {
    inputMethodAbility.off('inputStart');
    inputMethodAbility.off('inputStop');
  }
}

InputMethodService.ts

import { Want } from '@kit.AbilityKit';
import { InputMethodExtensionAbility } from '@kit.IMEKit';

import keyboardController from './model/KeyboardController';

// 输入法服务类,继承自InputMethodExtensionAbility
export default class InputDemoService extends InputMethodExtensionAbility {
  // 服务创建时调用
  onCreate(want: Want): void {
    keyboardController.onCreate(this.context);
  }

  // 服务销毁时调用
  onDestroy(): void {
    console.log("onDestroy.");
    keyboardController.onDestroy();
  }
}

Index.ets

import {
  numberSourceListData,
  sourceListType,
  letterSourceListDataRow1,
  letterSourceListDataRow2,
  letterSourceListDataRow3
} from './KeyboardKeyData';
import keyboardController from '../model/KeyboardController';

@Component
struct keyItem {
  private numberKeyValue: sourceListType = numberSourceListData[0];
  @State keyBgc: string = "#fff"
  @State keyFontColor: string = "#ff0a0505"

  @Styles
  pressedStyles(): void {
    .backgroundColor("#fff1f0f0")
  }

  @Styles
  normalStyles(): void {
    .backgroundColor(Color.White)
  }

  build() {
    Column() {
      Flex({
        direction: FlexDirection.Column,
        alignItems: ItemAlign.Center,
        justifyContent: FlexAlign.Center
      }) {
        Text(this.numberKeyValue.content).fontSize(20).fontColor(this.keyFontColor)
      }
    }
    .backgroundColor(this.keyBgc)
    .borderRadius(6)
    .width("8%")
    .height("100%")
    .onClick(() => {
      keyboardController.insertText(this.numberKeyValue.content);
    })
    .stateStyles({
      pressed: this.pressedStyles,
      normal: this.normalStyles
    })
  }
}

// 删除组件
@Component
export struct deleteItem {
  @State keyBgc: string = "#fff"
  @State keyFontColor: string = "#000"

  build() {
    Column() {
      Flex({
        direction: FlexDirection.Column,
        alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center
      }) {
        Text("删除").fontSize(20).fontColor(this.keyFontColor)
      }
    }
    .backgroundColor(this.keyBgc)
    .width("13%")
    .borderRadius(6)
    .onClick(() => {
      keyboardController.deleteForward(1);
    })
  }
}

// 数字键盘
@Component
struct ime_KeysMenu {
  private ime_Keys: sourceListType[] = numberSourceListData;

  build() {
    Row() {
      Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceEvenly }) {
        Flex({ justifyContent: FlexAlign.SpaceBetween }) {
          ForEach(this.ime_Keys, (item: sourceListType) => { // 键盘第一行
            keyItem({ numberKeyValue: item })
              .shadow(0.1)
              .borderRadius(102)
          }, (item: sourceListType) => item.content);
        }
        .padding({ top: "2%" })
        .width("96%")

        // Flex({ justifyContent: FlexAlign.SpaceBetween }) {
        //   deleteItem()
        // }
        // .width("96%")
        // .height("25%")
      }
    }
    .height(50)
  }
}

@Entry
@Component
struct Index {
  private numberList: sourceListType[] = numberSourceListData
  private letterList1: sourceListType[] = letterSourceListDataRow1;
  private letterList2: sourceListType[] = letterSourceListDataRow2;
  private letterList3: sourceListType[] = letterSourceListDataRow3;

  build() {
    Stack() {


      Flex({
        direction: FlexDirection.Column,
        alignItems: ItemAlign.Center,
        justifyContent: FlexAlign.End
      }) {

        Flex({
          direction: FlexDirection.Column,
          alignItems: ItemAlign.Center,
          justifyContent: FlexAlign.End
        }) {
          Row() {
            Text('林先生制作').fontSize(12) // 将用于整序阁的某一版本
              .fontWeight(700)
          }
          .width('100%')
          .backgroundColor(Color.White)
          .justifyContent(FlexAlign.Center)
          .padding(8)
          .borderWidth({ top: 0.25 })
          .borderColor('#ffacaaaa')

          ime_KeysMenu({
            ime_Keys: this.numberList
          })
          ime_KeysMenu({
            ime_Keys: this.letterList1
          })
          ime_KeysMenu({
            ime_Keys: this.letterList2
          })
          ime_KeysMenu({
            ime_Keys: this.letterList3
          })
        }
        .align(Alignment.End)
        .width("100%")
        .height("100%")
        .backgroundColor(Color.White)
      }
      .height("100%").align(Alignment.End).backgroundColor("#cdd0d7")
    }
    .position({ x: 0, y: 0 }).zIndex(99999)
  }
}

以上就是咱们的输入法IME开发的核心代码,包括键盘数据定义、键盘控制器和输入法服务。这些代码都是根据官方文档和代码文件整理出来的,确保了功能的完整性和准确性。

希望这些代码能帮助你在HarmonyOS上开发出自己的输入法应用。如果有啥问题或者需要进一步的帮助,随时来聊!👍🏻

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
分类
标签
收藏
回复
举报
回复
    相关推荐