鸿蒙NEXT开发【软键盘布局适配场景】应用框架开发

打印 上一主题 下一主题

主题 868|帖子 868|积分 2604

概述

软键盘是用户举行交互的重要途径之一,同时软键盘的弹出和收起,大概会影响到正在显示的UI元素,影响用户体验,出现如下常见的软键盘布局适配标题:


  • 重要信息被软键盘遮挡:当软键盘弹出时,输入框或其它重要UI元素大概会被键盘遮挡,导致用户无法看到或访问它们。
  • 软键盘弹出导致布局错位:内容大概会不适当上移,影响用户体验。
  • 软键盘弹出导致弹窗过分上抬:弹窗被键盘上顶,造成不好的体验。
本文将介绍以下知识帮助开发者了解软键盘的弹出和收起的控制、避让机制以及软键盘常见标题的办理方法。


  • 软键盘的弹出收起和监听
  • 软键盘避让机制
  • 软键盘避让常见标题
软键盘的弹出收起和监听

当用户点击输入框的时候,默认会弹出软键盘。但是某些场景下,须要对软键盘的弹出和收起举行控制。比如点击空缺区希望收起软键盘、进入页面的时候希望页面中的输入框能自动获焦并且弹出软键盘等,此外开发者大概须要根据软键盘的弹出和收起状态、软键盘的弹出高度来举行页面布局调整。本节将介绍软键盘的弹出收起控制、获取软键盘高度以及安全地域高度变化监听。
自动获焦弹出软键盘

偶然候进入页面,希望页面中的输入框能自动获焦并且弹出软键盘,方便用户直接输入,比如点击应用首页的搜索框,进入应用搜索页面。

可以通过将输入框的defaultFocus设置为true来实现。
  1. TextInput()
  2.   .defaultFocus(true)
复制代码
代码控制弹出软键盘

开发者可以使用全局的焦点控制对象FocusController的[requestFocus]方法,通过组件的id将焦点转移到组件树对应的实体节点,并且弹出软键盘。例如下面这个新增地址的示例,当用户未输入信息的时候,点击生存按钮,提示用户输入信息,并且弹出输入框,便于用户直接输入。

示例如下:
  1. TextInput({ placeholder: '请输入联系人姓名' })
  2.   .id('input1')
  3. Button('登录')
  4.   .onClick(() => {
  5.     this.getUIContext().getFocusController().requestFocus('input1');
  6.   })
复制代码
代码控制收起软键盘

通过全局的焦点控制对象FocusController的[clearFocus]方法,软键盘收起,例如下面的商品列表页面,点击搜索会收起软键盘。

示例代码如下:
  1. Button('搜索')
  2.   .onClick(() => {
  3.     this.getUIContext().getFocusController().clearFocus();
  4.   })
复制代码
监听获取软键盘高度

开发者还可以通过获取软键盘高度、监听软键盘的弹出和收起状态,来调整组件的位置来适配界面或者显示隐蔽某些组件。通过[window]模块的[on(‘keyboardHeightChange’)]方法开启固定态软键盘高度变化的监听,实时获取软键盘宽高。例如下面这个示例软键盘弹起后显示表情栏,软键盘收起后隐蔽表情栏。

上面效果图的实现示例代码如下,通过[on(‘keyboardHeightChange’)]方法实时获取软键盘高度赋值给变量keyboardHeight,当keyboardHeight为0的时候表现软键盘处于收起状态,此时隐蔽表情栏;keyboardHeight不为0的时候表现软键盘处于弹出状态,此时显示表情栏。
  1. import { window } from '@kit.ArkUI';
  2. @Entry
  3. @Component
  4. struct GetKeyboardHeightDemo {
  5.   @State keyboardHeight: number = 0; // 软键盘高度
  6.   aboutToAppear(): void {
  7.     window.getLastWindow(getContext(this)).then(currentWindow => {
  8.       currentWindow.on('keyboardHeightChange', (data: number) => {
  9.         this.keyboardHeight = px2vp(data);
  10.       })
  11.     })
  12.   }
  13.   build() {
  14.     Column() {
  15.       // ...
  16.       TextInput()
  17.       if (this.keyboardHeight > 0) {
  18.         Row() { // 表情栏
  19.           // ...
  20.         }
  21.         // ...
  22.       }
  23.     }
  24.   }
  25. }
复制代码
监听获取安全地域高度

通过[window]模块的[on(‘avoidAreaChange’)]方法开启当前窗口体系规避区变化的监听,获取内容可视地域巨细,同时也可以监听软键盘的弹出收起。开发者可以根据软键盘弹出之后的可视地域巨细去动态的调整布局中组件的高度去适配界面。
  1. import { window } from '@kit.ArkUI';
  2. @Entry
  3. @Component
  4. struct GetSafeAreaHeightDemo {
  5.   @State screenHeight: number = 0; // 安全区域高度
  6.   @State isKeyBoardHidden: boolean = false; // 软键盘是否隐藏
  7.   aboutToAppear(): void {
  8.     window.getLastWindow(getContext(this)).then(currentWindow => {
  9.       let property = currentWindow.getWindowProperties();
  10.       let avoidArea = currentWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_KEYBOARD);
  11.       // 初始化显示区域高度
  12.       this.screenHeight = px2vp(property.windowRect.height - avoidArea.topRect.height - avoidArea.bottomRect.height);
  13.       // 开启当前窗口系统规避区变化的监听
  14.       currentWindow.on('avoidAreaChange', data => {
  15.         if (data.type !== window.AvoidAreaType.TYPE_KEYBOARD) {
  16.           return;
  17.         }
  18.         if (data.area.bottomRect.height <= 0) {
  19.           this.isKeyBoardHidden = true;
  20.         } else {
  21.           this.isKeyBoardHidden = false;
  22.         }
  23.         this.screenHeight = px2vp(property.windowRect.height -data.area.topRect.height - data.area.bottomRect.height);
  24.         console.info(`screen height is: ${this.screenHeight}`);
  25.       })
  26.     })
  27.   }
  28.   build() {
  29.     Column() {
  30.       TextInput()
  31.     }
  32.   }
  33. }
复制代码
软键盘避让机制

办理软键盘的界面适配标题,首先须要了解在HarmonyOS体系中软键盘的避让机制是怎么样的。
软键盘默认避让效果

为了确保输入框不被软键盘挡住,体系默认提供了输入框避让软键盘的能力,联合下面这个输入框列表,介绍软键盘避让的主要表现形式。



  • 假如当前输入框不会被软键盘遮挡,则不上抬组件,如图所示点击输入框1,组件不会上抬。

  • 假如当前输入框会被软键盘遮挡,则上抬组件至刚幸亏软键盘上方显示完整的输入框,输入框上方的组件会跟着抬起,下方的组件不会露出,可以看到输入框11下方的输入框12不会露出。

  • 当软键盘弹出会覆盖输入框的时候,弹窗整领会上抬。

但是体系默认的软键盘避让形式只能包管输入框不被遮挡,输入框下方的组件大概就会被软键盘挡住,办理这一标题,这就须要了解软键盘的避让模式了。
软键盘避让模式

当用户在输入时,为了确保输入框不会被键盘遮挡,体系提供了避让模式来办理这一标题。开发者可以通过[setKeyboardAvoidMode]控制虚拟键盘抬起时页面的避让模式,避让模式有上抬模式和压缩模式两种,键盘抬起时默认页面避让模式为上抬模式。


  • 上抬模式(KeyboardAvoidMode.OFFSET):为了避让软键盘,Page内容会整体上抬。如下示例代码,软键盘弹出时,页面整体上抬:
  1. import { KeyboardAvoidMode, window } from '@kit.ArkUI';
  2. import { UIAbility } from '@kit.AbilityKit';
  3. export default class EntryAbility extends UIAbility {
  4.   onWindowStageCreate(windowStage: window.WindowStage): void {
  5.     windowStage.loadContent('pages/GetSafeAreaHeightDemo', (err) => {
  6.       // 上抬模式
  7.       windowStage.getMainWindowSync().getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.OFFSET);
  8.     });
  9.   }
  10. }
复制代码
表现效果如下,上抬整个页面实现软键盘避让:



  • 压缩模式(KeyboardAvoidMode.RESIZE):压缩Page的巨细,Page下设置百分比宽高的组件会跟随Page压缩,直接设置宽高的组件会按设置的固定巨细布局。设置KeyboardAvoidMode.RESIZE时,expandSafeArea([SafeAreaType.KEYBOARD],[SafeAreaEdge.BOTTOM])不见效。
  1. import { KeyboardAvoidMode, window } from '@kit.ArkUI';
  2. import { UIAbility } from '@kit.AbilityKit';
  3. export default class EntryAbility extends UIAbility {
  4.   onWindowStageCreate(windowStage: window.WindowStage): void {
  5.     windowStage.loadContent('pages/GetSafeAreaHeightDemo', (err) => {
  6.       // 压缩模式
  7.       windowStage.getMainWindowSync().getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.RESIZE);
  8.     });
  9.   }
  10. }
复制代码
表现效果如下,通过压缩内容地域高度实现软键盘避让:

设置组件不避让软键盘

前面介绍的避让模式,组件会为了避让软键盘而产生位移。偶然希望组件不要避让软键盘,比如软键盘的避让模式为上抬模式时,想要顶部的标题栏不要上抬。这种需求该怎么实现呢?这就须要了解[安全地域]和[expandSafeArea]属性了。
通过[expandSafeArea]属性支持组件不改变布局情况下扩展其绘制地域至安全区外,当设置expandSafeArea属性type为SafeAreaType.KEYBOARD的时候,即expandSafeArea([SafeAreaType.KEYBOARD]),体系会将软键盘地域视作安全区,从而不会避让软键盘。假如您希望某些组件不避让软键盘弹出,可以给组件设置expandSafeArea属性。
组件避让软键盘的示例效果如下,软键盘弹出时页面整体上抬,自定义标题栏固定不动

软键盘避让常见标题

下面列举一些常见的软键盘适配标题,帮助开发者了解软键盘的适配方法。
重要信息被软键盘遮挡

例如下面这个电子邮件的示例,内容由三部分组成:标题栏、内容地域和底部操作栏。当点击输入内容的输入框,软键盘会挡住底部的操作栏,影响用户体验,如下图所示:

对应的示例代码如下,其中标题栏和底部操作栏都是固定的高度56,内容地域高度是非固定高度layoutWeight(1),自顺应高度。
  1. @Entry
  2. @Component
  3. struct MailHomePage1 {
  4.   build() {
  5.     Column() {
  6.       this.NavigationTitle()
  7.       this.EmailContent()
  8.       this.BottomToolbar()
  9.     }
  10.     // ...
  11.   }
  12.   @Builder
  13.   NavigationTitle() {
  14.     Row() {
  15.       // ...
  16.     }
  17.     .width('100%')
  18.     .height(56)
  19.     // ...
  20.   }
  21.   /**
  22.    * Bottom toolbar area.
  23.    */
  24.   @Builder
  25.   BottomToolbar() {
  26.     Row({ space: 24 }) {
  27.       // ...
  28.     .width('100%')
  29.     .height(56)
  30.     // ...
  31.   }
  32.   @Builder
  33.   EmailContent() {
  34.     Column() {
  35.       // ...
  36.     }
  37.     .width('100%')
  38.     .layoutWeight(1)
  39.     // ...
  40.   }
  41. }
复制代码
开发者可以通过设置软键盘的避让模式为KeyboardAvoidMode.RESIZE(压缩模式),来办理底部操作栏被遮挡的标题,设置该属性后,软键盘的避让会通过压缩内容地域的高度来实现。示例代码如下:
  1. import { KeyboardAvoidMode, window } from '@kit.ArkUI';
  2. import { UIAbility } from '@kit.AbilityKit';
  3. export default class EntryAbility extends UIAbility {
  4.   onWindowStageCreate(windowStage: window.WindowStage): void {
  5.     windowStage.loadContent('pages/GetSafeAreaHeightDemo', (err) => {
  6.       // 压缩模式
  7.       windowStage.getMainWindowSync().getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.RESIZE);
  8.     });
  9.   }
  10. }
复制代码
须要注意的是内容地域高度的设置须要用百分比的方式实现,效果图如下:

通过监听软键盘弹出,实现软键盘避让
上面这个示例开发者还可以通过window模块的[getWindowAvoidArea]方法,监听获取软键盘弹出,获取安全显示地域高度动态设置页面高度。示例代码如下:
  1. import { window } from '@kit.ArkUI';
  2. @Entry
  3. @Component
  4. struct MailHomePage2 {
  5.   @State message: string = 'Hello World';
  6.   @State screenHeight: number = 0;
  7.   @State isKeyBoardHidden: boolean = false;
  8.   aboutToAppear(): void {
  9.     window.getLastWindow(getContext(this)).then(currentWindow => {
  10.       let property = currentWindow.getWindowProperties();
  11.       let avoidArea = currentWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM);
  12.       // 初始化显示区域高度
  13.       this.screenHeight = px2vp(property.windowRect.height - avoidArea.topRect.height - avoidArea.bottomRect.height);
  14.       // 监视软键盘的弹出和收起
  15.       currentWindow.on('avoidAreaChange', async data => {
  16.         if (data.type !== window.AvoidAreaType.TYPE_KEYBOARD) {
  17.           return;
  18.         }
  19.         if (data.area.bottomRect.height <= 0) {
  20.           this.isKeyBoardHidden = true;
  21.         } else {
  22.           this.isKeyBoardHidden = false;
  23.         }
  24.         this.screenHeight = px2vp(property.windowRect.height - avoidArea.topRect.height - data.area.bottomRect.height);
  25.       })
  26.     })
  27.   }
  28.   build() {
  29.     Column() {
  30.       this.NavigationTitle()
  31.       this.EmailContent()
  32.       this.BottomToolbar()
  33.     }
  34.     .width('100%')
  35.     .height(this.screenHeight) // 动态设置可视区域高度
  36.     .expandSafeArea([SafeAreaType.KEYBOARD])
  37.     .backgroundColor('#F1F3F5')
  38.   }
  39.   // ...
  40. }
复制代码
当体系的避让机制大概满足不了开发者的一些需求的时候,开发者可以实验监听软键盘弹出,根据获取的安全地域或者软键盘高度,来调整布局巨细和位置来避让软键盘。
软键盘弹出导致布局错位

内容向上滚动避让,顶部固定
例如下面这样的一个聊天界面,顶部是一个自定义的标题,下方为可滚动聊天消息地域,底部是消息输入框,示例代码如下:
  1. @Entry
  2. @Component
  3. struct ContactPage {
  4.   build() {
  5.     Column() {
  6.       Row() { // 顶部自定义标题栏
  7.         // ...
  8.       }
  9.       .width('100%')
  10.       .height('12%')
  11.       List() { // 聊天消息区域
  12.         // ...
  13.       }
  14.       .width('100%')
  15.       .height('76%')
  16.       Column() { // 底部消息输入框
  17.         // ...
  18.       }
  19.       .width('100%')
  20.       .height('12%')
  21.     }
  22.     .width('100%')
  23.     .height('100%')
  24.   }
  25. }
复制代码
但是由于软键盘避让默认是上抬模式,会把整个页面向上抬起,所以标题也会被顶上去,如下图所示。

如今需求希望顶部标题固定,点击底部输入框软键盘弹起的时候,标题不上抬,只有内容地域上抬。效果图如下:

想要顶部标题不被软键盘向上抬,须要给对应的组件设置 .expandSafeArea([SafeAreaType.KEYBOARD])}属性,使标题组件不避让键盘,示例代码如下:
  1. @Entry
  2. @Component
  3. struct ContactPage {
  4.   build() {
  5.     Column() {
  6.       Row() { // 顶部自定义标题栏
  7.         // ...
  8.       }
  9.       .width('100%')
  10.       .height('12%')
  11.       .expandSafeArea([SafeAreaType.KEYBOARD])
  12.       .zIndex(1)
  13.       List() { // 聊天消息区域
  14.         // ...
  15.       }
  16.       .width('100%')
  17.       .height('76%')
  18.       Column() { // 底部消息输入框
  19.         // ...
  20.       }
  21.       .width('100%')
  22.       .height('12%')
  23.     }
  24.     .width('100%')
  25.     .height('100%')
  26.   }
  27. }
复制代码
软键盘弹出导致弹窗过分上抬

自定义弹窗被键盘顶起 ,影响用户体验
在软键盘体系避让机制中介绍过,弹窗为避让软键盘会举行避让,整体向上抬,这样大概会影响用户体验。比如下面这个评论里列表的弹窗,使用@CustomDialog实现的,示例代码如下:
  1. @CustomDialog
  2. struct CommentDialog {
  3.   listData: string[] = ['评论1', '评论2', '评论3', '评论4', '评论5', '评论6', '评论7', '评论8'];
  4.   controller?: CustomDialogController;
  5.   build() {
  6.     Column() {
  7.       Text('评论')
  8.         .fontSize(20)
  9.         .fontWeight(FontWeight.Medium)
  10.       List() {
  11.         ForEach(this.listData, (item: string) => {
  12.           ListItem() {
  13.             Text(item)
  14.               .height(80)
  15.               .fontSize(20)
  16.           }
  17.         }, (item: string) => item)
  18.       }
  19.       .scrollBar(BarState.Off)
  20.       .width('100%')
  21.       .layoutWeight(1)
  22.       TextInput({ placeholder: 'Please input content' })
  23.         .height(40)
  24.         .width('100%')
  25.     }
  26.     .padding(12)
  27.   }
  28. }
  29. @Entry
  30. @Component
  31. struct CustomDialogDemo {
  32.   dialogController: CustomDialogController | null = new CustomDialogController({
  33.     builder: CommentDialog(),
  34.     alignment: DialogAlignment.Bottom,
  35.     cornerRadius: 0,
  36.     width: '100%',
  37.     height: '80%'
  38.   })
  39.   build() {
  40.     Column() {
  41.       Button('click me')
  42.         .onClick(() => {
  43.           if (this.dialogController !== null) {
  44.             this.dialogController.open();
  45.           }
  46.         })
  47.     }
  48.     .height('100%')
  49.     .width('100%')
  50.     .justifyContent(FlexAlign.Center)
  51.   }
  52. }
复制代码
当用户点击弹窗底部的输入框的时候,弹窗会整体上抬,输入框上抬的距离也过多。

为了办理以上标题,可以使用[Navigation.Dialog],通过设置NavDestination的mode为NavDestinationMode.DIALOG弹窗范例,此时整个NavDestination默认透明显示,示例代码如下:
  1. @Entry
  2. @Component
  3. struct NavDestinationModeDemo {
  4.   @Provide('NavPathStack') pageStack: NavPathStack = new NavPathStack()
  5.   @Builder
  6.   PagesMap(name: string) {
  7.     if (name === 'DialogPage') {
  8.       DialogPage()
  9.     }
  10.   }
  11.   build() {
  12.     Navigation(this.pageStack) {
  13.       Column() {
  14.         Button('click me')
  15.           .onClick(() => {
  16.             this.pageStack.pushPathByName('DialogPage', '');
  17.           })
  18.       }
  19.       .height('100%')
  20.       .width('100%')
  21.       .justifyContent(FlexAlign.Center)
  22.     }
  23.     .mode(NavigationMode.Stack)
  24.     .navDestination(this.PagesMap)
  25.   }
  26. }
  27. @Component
  28. export struct DialogPage {
  29.   @Consume('NavPathStack') pageStack: NavPathStack;
  30.   listData: string[] = ['评论1', '评论2', '评论3', '评论4', '评论5', '评论6', '评论7', '评论8'];
  31.   build() {
  32.     NavDestination() {
  33.       Stack({ alignContent: Alignment.Bottom }) {
  34.         Column() {
  35.           Text('评论')
  36.             .fontSize(20)
  37.             .fontWeight(FontWeight.Medium)
  38.           List() {
  39.             ForEach(this.listData, (item: string) => {
  40.               ListItem() {
  41.                 Text(item)
  42.                   .height(80)
  43.                   .fontSize(20)
  44.               }
  45.             }, (item: string) => item)
  46.           }
  47.           .scrollBar(BarState.Off)
  48.           .width('100%')
  49.           .layoutWeight(1)
  50.           TextInput({ placeholder: 'Please input content' })
  51.             .height(40)
  52.             .width('100%')
  53.         }
  54.         .backgroundColor(Color.White)
  55.         .height('75%')
  56.         .width('100%')
  57.         .padding(12)
  58.       }
  59.       .height('100%')
  60.       .width('100%')
  61.     }
  62.     .backgroundColor('rgba(0,0,0,0.2)')
  63.     .hideTitleBar(true)
  64.     .mode(NavDestinationMode.DIALOG)
  65.   }
  66. }
复制代码
此外还须要设置软键盘避让模式为压缩模式,示例代码如下:
  1. import { KeyboardAvoidMode, window } from '@kit.ArkUI';
  2. import { UIAbility } from '@kit.AbilityKit';
  3. export default class EntryAbility extends UIAbility {
  4.   onWindowStageCreate(windowStage: window.WindowStage): void {
  5.     windowStage.loadContent('pages/GetSafeAreaHeightDemo', (err) => {
  6.       // 压缩模式
  7.       windowStage.getMainWindowSync().getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.RESIZE);
  8.     });
  9.   }
  10. }
复制代码
运行效果如下,点击输入框后,内容地域会举行压缩,弹窗整体不会发生上抬。

软键盘弹出时,防止Toast上抬
软键盘默认弹出的时候会将**promptAction.showToast**的Toast向上抬起,偶然候大概会造成不好的体验。例如下面这个登录的示例,当Toast显示的时候,弹出软键盘会导致Toast上抬,挡住关键信息登录按钮,如下图所示:

可以通过设置showMode为ToastShowMode.TOP_MOST来实现。showMode用于设置弹窗是否显示在应用之上,默认显示在应用内,设置为ToastShowMode.TOP_MOST之后,Toast可以显示在应用之上。
  1. Button('登录')
  2.   // ...
  3.   .onClick(() => {
  4.     promptAction.showToast({
  5.       message: '账号或密码不能为空',
  6.       showMode: promptAction.ToastShowMode.DEFAULT
  7.     });
  8.   })
复制代码
效果图如下:


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

鼠扑

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表