0


HarmonyOS鸿蒙开发实战(5.0)自定义安全键盘场景实践

鸿蒙HarmonyOS开发实战往期必看文章:(持续更新......)

HarmonyOS NEXT应用开发性能实践总结(持续更新......)

HarmonyOS NEXT应用开发案例实践总结合集(持续更新......)

一分钟了解”纯血版!鸿蒙HarmonyOS Next应用开发!

最新版!“非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线!(从零基础入门到精通)


介绍

金融类应用在密码输入时,一般会使用自定义安全键盘。本示例介绍如何使用TextInput组件实现自定义安全键盘场景,主要包括TextInput.customKeyboard绑定自定义键盘、自定义键盘布局和状态更新等知识点。

效果图预览

实现思路

1. 使用TextInput的customKeyboard的属性方法来设置自定义键盘

当设置自定义键盘时,输入框激活后不会打开系统输入法,而是加载应用指定的自定义组件,针对系统键盘的enterKeyType属性设置将无效。自定义键盘采用覆盖原始界面的方式呈现,不会对应用原始界面产生压缩或者上提。默认在输入控件失去焦点时,关闭自定义键盘,开发者也可以通过TextInputController.stopEditing方法控制键盘关闭。

2. 自定义键盘布局

键盘枚举类型:

  • 键盘类型分为数字键盘,大写、小写键盘,特殊字符键盘
  • 键盘按键类型分为输入操作INPUT、删除操作DELETE、切换数字键盘操作NUMERIC、切换大小写键盘CAPSLOCK、切换数字键盘SPECIAL共五种类型
  1. /**
  2. * 键盘类型枚举
  3. */
  4. export enum EKeyboardType {
  5. NUMERIC, //数字键盘
  6. UPPERCASE, // 大写字母键盘
  7. LOWERCASE, // 小写字母键盘
  8. SPECIAL, // 特殊字符键盘
  9. }
  10. /**
  11. * 键盘按键类型枚举
  12. */
  13. export enum EKeyType {
  14. INPUT, // 输入类型,输入具体的值
  15. DELETE, // 删除一个输入字符
  16. NUMERIC, // 切换数字键盘
  17. CAPSLOCK, // 切换大小写键盘
  18. SPECIAL, // 切换特殊字符键盘
  19. }

在真实业务场景下,自定义安全键盘数据包括值、UI属性、位置等都通过数据请求来下发,键盘按键数据接口定义如下:

  1. /**
  2. * 键盘按键数据接口
  3. */
  4. export interface IKeyAttribute {
  5. label: string | Resource;
  6. value?: string;
  7. type?: EKeyType;
  8. fontSize?: number;
  9. fontColor?: string | Color;
  10. backgroundColor?: string | Color;
  11. position?: [number, number, number, number];
  12. }

自定义键盘布局:分为标题栏和键盘两部分,键盘使用Grid布局,每个按键GridItem的值、UI属性和位置都通过数据请求下发,不需要额外计算。

数字键盘为4*3的网格布局,但是大小写键盘和特殊字符键盘的布局为不规则布局,如果设置为4 * 10的网格,有的按键占用1 * 1.5,但是GridItem属性不支持占用非整数列。本文将该场景下将网格拆分为更小的单元,为4 * 20网格布局,每个字母按键占1 * 2,删除按键则占1 * 3,空格则占1 * 10,这样就保证每个按键都要占用整数单元。

  1. Column() {
  2. this.titleBar();
  3. Grid() {
  4. ForEach(this.items, (item: IKeyAttribute) => {
  5. GridItem() {
  6. this.myGridItem(item)
  7. }
  8. .width('100%')
  9. .height(this.itemHeight)
  10. .rowStart(item?.position?.[0])
  11. .columnEnd(item?.position?.[1])
  12. .columnStart(item?.position?.[2])
  13. .columnEnd(item?.position?.[3])
  14. .backgroundColor(item.backgroundColor)
  15. .borderRadius($r("app.integer.key_border_radius"))
  16. .onClick(() => {
  17. ....
  18. })
  19. }, (item: IKeyAttribute, index: number) => JSON.stringify(item) + index)
  20. }
  21. .margin({ bottom: $r("app.integer.key_board_marin_bottom") })
  22. .columnsTemplate(this.curKeyboardType === EKeyboardType.NUMERIC ? "1fr 1fr 1fr" :
  23. "1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr")
  24. .rowsTemplate("1fr 1fr 1fr 1fr") // Grid高度均分成4份
  25. .rowsGap(this.rowSpace) // 设置行间距
  26. .columnsGap(this.columnSpace) // 设置列间距
  27. .width('100%')
  28. .height(this.itemHeight * this.rowCount + this.rowSpace * (this.rowCount - 1))
  29. }
  30. .width('100%')
  31. .padding({ left: this.columnSpace, right: this.columnSpace })
  32. .backgroundColor(Color.Black)
  33. }
3. 状态更新

主要是子组件自定义键盘的按键事件如何传递到父组件,可以在父组件定义好键盘按键事件响应函数onKeyboardEvent,传递给子组件,然后子组件按键时调用父组件传递过来的onKeyboardEvent即可。需要注意的是,在子组件中,必须定义inputValue且使用@Link装饰器,这样能保证子组件调用时onKeyboardEvent时inputValue不为空,父子组件数据双向更新。

  1. @Component
  2. export struct CustomSafeKeyboardView {
  3. @State inputValue: string = '';
  4. @State items: IKeyAttribute[] = numericKeyData;
  5. @State curKeyboardType: EKeyboardType = EKeyboardType.NUMERIC;
  6. controller: TextInputController = new TextInputController();
  7. /**
  8. * 键盘按键事件响应函数
  9. * @param item
  10. */
  11. onKeyboardEvent(item: IKeyAttribute) {
  12. switch (item.type) {
  13. // 输入类型,更新输入内容
  14. case EKeyType.INPUT:
  15. this.inputValue += item.value;
  16. break;
  17. // 删除一个已输入的末尾字符
  18. case EKeyType.DELETE:
  19. this.inputValue = this.inputValue.slice(0, -1);
  20. break;
  21. // 切换数字字符键盘
  22. case EKeyType.NUMERIC:
  23. if (this.curKeyboardType !== EKeyboardType.NUMERIC) {
  24. this.curKeyboardType = EKeyboardType.NUMERIC;
  25. this.items = numericKeyData;
  26. }
  27. break;
  28. // 切换大小写
  29. case EKeyType.CAPSLOCK:
  30. if (this.curKeyboardType === EKeyboardType.LOWERCASE) {
  31. // 切换大写字母键盘
  32. this.curKeyboardType = EKeyboardType.UPPERCASE;
  33. this.items = upperCaseKeyData;
  34. } else {
  35. // 切换小写字母键盘
  36. this.curKeyboardType = EKeyboardType.LOWERCASE;
  37. this.items = lowerCaseKeyData;
  38. }
  39. break;
  40. // 切换特殊字符键盘
  41. case EKeyType.SPECIAL:
  42. if (this.curKeyboardType !== EKeyboardType.SPECIAL) {
  43. this.curKeyboardType = EKeyboardType.SPECIAL;
  44. this.items = specialKeyData;
  45. }
  46. break;
  47. default:
  48. console.info(`Sorry, we are out of input type.`);
  49. }
  50. }
  51. /**
  52. * 自定义键盘组件Builder
  53. */
  54. @Builder
  55. customKeyboardBuilder() {
  56. CustomKeyboard({
  57. items: this.items,
  58. inputValue: this.inputValue,
  59. curKeyboardType: this.curKeyboardType,
  60. onKeyboardEvent: this.onKeyboardEvent,
  61. controller: this.controller
  62. })
  63. }
  64. build() {
  65. Column() {
  66. Row()
  67. .height($r("app.integer.row_height"))
  68. Image($r("app.media.avatar"))
  69. .width($r("app.integer.avatar_weight"))
  70. .height($r("app.integer.avatar_height"))
  71. .objectFit(ImageFit.Fill)
  72. Text($r("app.string.account_name"))
  73. .fontSize($r("app.integer.text_font_size"))
  74. .margin({ top: $r("app.integer.common_margin_padding") })
  75. TextInput({
  76. text: this.inputValue,
  77. placeholder: $r("app.string.placeholder"),
  78. controller: this.controller
  79. })// 绑定自定义键盘
  80. .type(InputType.Password)
  81. .customKeyboard(this.customKeyboardBuilder())// 绑定自定义安全键盘
  82. .height($r("app.integer.text_input_height"))
  83. .border(null)
  84. .margin({ top: $r("app.integer.common_margin_padding") })
  85. Button($r("app.string.login_button_label"))
  86. .type(ButtonType.Capsule)
  87. .fontSize($r("app.integer.login_button_font_size"))
  88. .width($r("app.integer.login_button_width"))
  89. .height($r("app.integer.login_button_height"))
  90. .margin({ top: $r("app.integer.login_button_margin") })
  91. .backgroundColor(Color.Pink)
  92. .onClick(() => {
  93. this.controller.stopEditing();
  94. })
  95. }
  96. .width($r("app.string.one_hundred_percent"))
  97. .height($r("app.string.one_hundred_percent"))
  98. .padding($r("app.integer.common_margin_padding"))
  99. }
  100. }

高性能知识点

不涉及

工程结构&模块类型

  1. customsafekeyboard // har类型
  2. |---components // 自定义组件
  3. | ---CustomKeyboard.ets
  4. |---model // 模型层
  5. | ---Constants // 定义常量数据
  6. |---CustomSafeKeyboardView.ets // 主页面

模块依赖

  1. 依赖common模块来实现日志的打印
  2. 依赖路由模块,供entry模块实现路由导航

最后

小编在之前的鸿蒙系统扫盲中,有很多朋友给我留言,有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)路线图、学习视频、文档用来跟着学习是非常有必要的。

如果你是一名有经验的资深Android移动开发、Java开发、前端开发、对鸿蒙感兴趣以及转行人员

鸿蒙 NEXT 全栈开发学习笔记 希望这一份鸿蒙学习文档能够给大家带来帮助~

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


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

该路线图包含基础技能、就业必备技能、多媒体技术、六大电商APP、进阶高级技能、实战就业级设备开发,不仅补充了华为官网未涉及的解决方案

路线图适合人群:

IT开发人员:想要拓展职业边界
零基础小白:鸿蒙爱好者,希望从0到1学习,增加一项技能。
技术提升/进阶跳槽:发展瓶颈期,提升职场竞争力,快速掌握鸿蒙技术

2.视频学习教程+学习PDF文档

**HarmonyOS Next 最新全套视频教程 **全球开发者的开源社区,开源代码

**纯血版鸿蒙全套学习文档(面试、文档、全套视频等) **全球开发者的开源社区,开源代码

​​

《鸿蒙大厂面试真题》GitCode - 全球开发者的开源社区,开源代码

总结

参与鸿蒙开发,你要先认清适合你的方向,如果是想从事鸿蒙应用开发方向的话,可以参考本文的学习路径,简单来说就是:为了确保高效学习,建议规划清晰的学习路线

标签: harmonyos 华为 鸿蒙

本文转载自: https://blog.csdn.net/weixin_55362248/article/details/142522276
版权归原作者 让开,我要吃人了 所有, 如有侵权,请联系我们删除。

“HarmonyOS鸿蒙开发实战(5.0)自定义安全键盘场景实践”的评论:

还没有评论