基于原生能力的键盘控制

基于原生能力的键盘控制

  • 前言
  • 一、进入页面TextInput获焦
    • 1、方案
    • 2、核心代码
  • 二、点击按钮或其他事件触发TextInput获焦
    • 1、方案
    • 2、核心代码
  • 三、键盘弹出后只上抬特定的输入组件
    • 1、方案
    • 2、核心代码
  • 四、监听键盘高度
    • 1、方案
    • 2、核心代码
  • 五、设置窗口在键盘抬起时的页面避让模式为上抬,压缩
    • 1、方案
    • 2、核心代码
  • demo代码
    • Index.ets
    • Login.ets
    • Register.ets


前言

应用通常使用键盘的方式,系统键盘的弹出收起,获焦失焦,高度监听,安全避让等。

应用经常会遇到如下的业务诉求:

场景一:进入页面TextInput获焦,弹出系统键盘。

场景二:点击按钮或其他事件触发TextInput获焦,弹出系统键盘。

场景三:键盘弹出后只上抬特定的输入组件。

场景四:监听键盘高度,在键盘弹出后让组件上移,键盘收起后让组件恢复。

场景五:设置窗口在键盘抬起时的页面避让模式为上抬,压缩。

一、进入页面TextInput获焦

1、方案

通过defaultFocus通用属性设置,实现第一次进入页面后弹出键盘

2、核心代码

TextInput({ text: $$this.username, placeholder: '请输入用户名' }).placeholderColor('#D4D3D1').backgroundColor(this.isUserNameFocus ? '#80FFFFFF' : '#ffffff').width(260).borderRadius(8).id('username').margin({ top: 10, bottom: 10 }).onFocus(() => {this.isUserNameFocus = true}).onBlur(() => {this.isUserNameFocus = false}).defaultFocus(true)   // 进入页面默认获焦

二、点击按钮或其他事件触发TextInput获焦

1、方案

通过focusControl.requestFocus,实现输入账号后,点击登录按钮后,代码主动设置TextInput获取焦点

2、核心代码

Button('登  录').width(200).height(45).fontSize(28).type(ButtonType.Normal).backgroundColor('#30FFFFFF').border({ width: 1, color: Color.White, radius: 8 }).margin({ top: 50, bottom: 60 }).onClick(() => {let LoginForm: LoginForm = {username: this.username,password: this.password}let requestId = ''if (!LoginForm.username) {requestId = 'username'} else if (!LoginForm.password) {requestId = 'password'} else {promptAction.showToast({ message: 'Login success' })return}let res = focusControl.requestFocus(requestId) // 使选中的this.selectId的组件获焦,这里要注意获焦的id要与组件的id保持一致promptAction.showToast({ message: requestId + '不能为空' })})

三、键盘弹出后只上抬特定的输入组件

1、方案

通过expandSafeArea通用属性设置,实现只上抬红框圈住的特定组件

2、核心代码

Column(){// 在页面跟容器设置安全区域这样页面就不会上抬了只有对应的输入框会进行上抬
}
.expandSafeArea([SafeAreaType.KEYBOARD], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])

四、监听键盘高度

1、方案

先通过expandSafeArea禁止自动键盘弹出上移页面。然后通过window.on(‘avoidAreaChange’)和windowClass.on(‘keyboardHeightChange’),实现监听键盘高度,上抬整个页面view,让输入框(生命周期价值输入框)组件能显示在键盘上方

2、核心代码

@State screenHeight: Length = 0onPageShow(): void {// ...window.getLastWindow(getContext(this)).then(currentWindow => {let property = currentWindow.getWindowProperties();let avoidArea = currentWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM);// 初始化显示区域高度this.screenHeight = px2vp(property.windowRect.height - avoidArea.topRect.height - avoidArea.bottomRect.height);// 监视软键盘的弹出和收起currentWindow.on('keyboardHeightChange', async data => {// 这里通过监听键盘高度变化来改变跟容器高度变化this.screenHeight = px2vp(property.windowRect.height - avoidArea.topRect.height - data);})})// ...
}Column() {...
}
.width('100%')
.height(this.screenHeight)
.expandSafeArea([SafeAreaType.KEYBOARD], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])

五、设置窗口在键盘抬起时的页面避让模式为上抬,压缩

1、方案

点击生命周期输入框,通过windowStage.getMainWindowSync().getUIContext().setKeyboardAvoidMode,实现设置窗口在键盘抬起时的页面避让模式,这种情况下当键盘弹起的时候页面会自动压缩

2、核心代码

onPageShow(): void {// ...this.windowStage.getMainWindowSync().getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.RESIZE)// 在RESIZE模式下当键盘弹起的时候页面会进行压缩// ...
}onPageHide(): void {this.windowStage.getMainWindowSync().getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.OFFSET)// 在OFFSET模式下当键盘弹起的时候页面会进行上抬
}

demo代码

Index.ets

import { router } from '@kit.ArkUI';@Entry
@Component
struct Index {build() {Row() {Column() {Button('进入页面获焦').margin({ top: 10, bottom: 10 }).onClick(() => {router.pushUrl({ url: 'pages/Login', params: { pageId: '1' } })})Button('事件触发主动获焦').margin({ top: 10, bottom: 10 }).onClick(() => {router.pushUrl({ url: 'pages/Login', params: { pageId: '2' } })})Button('键盘弹出不上移组件').margin({ top: 10, bottom: 10 }).onClick(() => {router.pushUrl({ url: 'pages/Register', params: { pageId: '3' } })})Button('监听键盘高度变化').margin({ top: 10, bottom: 10 }).onClick(() => {router.pushUrl({ url: 'pages/Register', params: { pageId: '4' } })})Button('设置页面避让模式').margin({ top: 10, bottom: 10 }).onClick(() => {router.pushUrl({ url: 'pages/Register', params: { pageId: '5' } })})}.width('100%')}.height('100%')}
}

Login.ets

import { promptAction, router } from '@kit.ArkUI'interface LoginForm {username: stringpassword: string
}export interface routerParam {pageId: string
}@Entry
@Component
struct Login {@State username: string = ''@Watch('passwordChange') @State password: string = ''@State isUserNameFocus: boolean = false@State isPasswordFocus: boolean = false@State rememberPassword: boolean = false@State showPasswordIcon: boolean = falseprivate controller: TextInputController = new TextInputController()@State routerParams: routerParam = { pageId: '0' }passwordChange() {this.showPasswordIcon = !!this.password}onPageShow(): void {this.routerParams = router.getParams() as routerParamconsole.log(this.routerParams.pageId)}build() {Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {Row() {Image($r('app.media.avatar')).width(60).height(60)}.borderRadius(50).width(100).height(100).justifyContent(FlexAlign.Center).backgroundColor('#FFFFFF').margin({ bottom: 30 })TextInput({ text: $$this.username, placeholder: '请输入用户名', controller: this.controller }).placeholderColor('#D4D3D1').backgroundColor(this.isUserNameFocus ? '#80FFFFFF' : '#ffffff').width(260).borderRadius(8).id('username').margin({ top: 10, bottom: 10 }).onFocus(() => {this.isUserNameFocus = true}).onBlur(() => {this.isUserNameFocus = false}).defaultFocus(this.routerParams.pageId === '1') // 进入页面默认获焦TextInput({ text: $$this.password, placeholder: '请输入密码', controller: this.controller }).placeholderColor('#D4D3D1').type(InputType.Password).showPasswordIcon(this.showPasswordIcon).backgroundColor(this.isPasswordFocus ? '#80FFFFFF' : '#ffffff').width(260).borderRadius(8).id('password').margin({ top: 10, bottom: 10 }).onFocus(() => {this.isPasswordFocus = true}).onBlur(() => {this.isPasswordFocus = false})Row() {Checkbox().select($$this.rememberPassword).unselectedColor('#ffffff').width(16).borderRadius(8).backgroundColor(Color.White)Text('记住密码').fontColor('#ffffff').onClick(() => {this.rememberPassword = !this.rememberPassword})}.width(260)Button('登  录').width(200).height(45).fontSize(28).type(ButtonType.Normal).backgroundColor('#30FFFFFF').border({ width: 1, color: Color.White, radius: 8 }).margin({ top: 50, bottom: 60 }).onClick(() => {let LoginForm: LoginForm = {username: this.username,password: this.password}let requestId = ''// todo: 无法使用for..in遍历对象if (!LoginForm.username) {requestId = 'username'} else if (!LoginForm.password) {requestId = 'password'} else {promptAction.showToast({ message: 'Login success' })return}focusControl.requestFocus(requestId) // 使选中的this.selectId的组件获焦promptAction.showToast({ message: requestId + '不能为空' })})Row() {Text('忘记密码').fontColor(Color.White)Text('注册').fontColor(Color.White).onClick(() => {router.pushUrl({ url: 'pages/Register', params: { pageId: '3' } })})}.justifyContent(FlexAlign.SpaceBetween).width(260)}.width('100%').height('100%').expandSafeArea([SafeAreaType.SYSTEM, SafeAreaType.KEYBOARD], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]).backgroundImage($r('app.media.bg')).backgroundImageSize(ImageSize.Cover).onTouch(() => {this.controller.stopEditing()})}
}

Register.ets

import { KeyboardAvoidMode, router, window } from '@kit.ArkUI';
import { routerParam } from './Login'@Entry
@Component
struct Register {@State routerParams: routerParam = { pageId: '0' }@State screenHeight: Length = '100%'private windowStage = AppStorage.get('windowStage') as window.WindowStageonPageShow(): void {this.routerParams = router.getParams() as routerParamif (this.routerParams.pageId == '5') {this.windowStage.getMainWindowSync().getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.RESIZE)}if (this.routerParams.pageId == '4') {window.getLastWindow(getContext(this)).then(currentWindow => {let property = currentWindow.getWindowProperties();let avoidArea = currentWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM);// 初始化显示区域高度this.screenHeight = px2vp(property.windowRect.height - avoidArea.topRect.height - avoidArea.bottomRect.height);// 监视软键盘的弹出和收起currentWindow.on('avoidAreaChange', async data => {if (data.type !== window.AvoidAreaType.TYPE_KEYBOARD) {return;}this.screenHeight =px2vp(property.windowRect.height - avoidArea.topRect.height - data.area.bottomRect.height);})})}}onPageHide(): void {this.windowStage.getMainWindowSync().getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.OFFSET)}build() {Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Start }) {Row() {Image($r('app.media.back')).width(24).position({ x: 16, y: 10 }).onClick(() => {router.back()})Text('用户注册').fontSize(24).fontWeight(FontWeight.Bold)}.height(45).borderWidth({ bottom: 1 }).borderColor('#EAEEF5').width('100%').justifyContent(FlexAlign.Center)Column() {Image($r('app.media.logo')).width(240)}// 表单主体List({ space: 16 }) {ListItem() {FormItem({ label: '用户名', placeholder: '请输入用户名' })}ListItem() {FormItem({ label: '密码', placeholder: '请输入密码' })}ListItem() {FormItem({ label: '手机号', placeholder: '请输入手机号' })}ListItem() {FormItem({ label: '邮箱', placeholder: '请输入邮箱地址' })}ListItem() {Column() {Text('个人简介').margin({ bottom: 16 })TextArea({ placeholder: '介绍点啥吧...' }).borderRadius(0).borderWidth({ bottom: 1 }).borderColor('#EAEEF5').height(100)}.alignItems(HorizontalAlign.Start)}}.padding(10).layoutWeight(1).edgeEffect(EdgeEffect.None).scrollBar(BarState.Off).expandSafeArea([SafeAreaType.KEYBOARD], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])Row() {Button('提交').type(ButtonType.Normal).fontColor(Color.White).backgroundColor('#59BEB7').width('100%')}.padding(16).shadow({ radius: 20, color: '#30000000' }).width('100%').expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM])}.width('100%').height(this.screenHeight).expandSafeArea([SafeAreaType.KEYBOARD], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])}
}@Component
struct FormItem {@Prop label: string@Prop placeholder: string@State value: string = ''build() {Column() {Text(this.label).margin({ bottom: 16 })TextInput({ text: this.value, placeholder: this.placeholder }).backgroundColor(Color.Transparent).borderRadius(0).borderWidth({ bottom: 1 }).borderColor('#EAEEF5')}.alignItems(HorizontalAlign.Start).expandSafeArea([SafeAreaType.KEYBOARD], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/910291.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/910291.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大数据治理域——数据存储与成本管理

摘要 本文主要探讨了数据存储与成本管理的多种策略。介绍了数据压缩技术,如MaxCompute的archive压缩方法,通过RAID file形式存储数据,可有效节省空间,但恢复时间较长,适用于冷备与日志数据。还详细阐述了数据生命周期…

国产Linux银河麒麟操作系统上使用自带openssh远程工具SSH方式登陆华为交换机或服务器

在Windows和Linux Debian系统上我一直使用electerm远程工具访问服务器或交换机, 一、 electerm简介 简介:electerm是一款开源免费的SSH工具,具有良好的跨平台兼容性,适用于Windows、macOS、Linux以及麒麟操作系统。特点&#xf…

Logback 在java中的使用

Logback 是 Java 应用中广泛使用的日志框架&#xff0c;以下是其核心使用方法及最佳实践&#xff1a; 1. 引入依赖 在 Maven 或 Gradle 项目中添加 Logback 及 SLF4J 依赖&#xff1a; <!-- Maven --> <dependency><groupId>ch.qos.logback</groupId>…

Axure应用交互设计:中继器—整行、条件行、当前行赋值

亲爱的小伙伴,如有帮助请订阅专栏!跟着老师每课一练,系统学习Axure交互设计课程! Axure产品经理精品视频课https://edu.csdn.net/course/detail/40420 课程主题:对中继器中:整行、符合某种条件的任意行、当前行的赋值操作 课程视频:

ToolsSet之:TTS及Morse编解码

ToolsSet是微软商店中的一款包含数十种实用工具数百种细分功能的工具集合应用&#xff0c;应用基本功能介绍可以查看以下文章&#xff1a; Windows应用ToolsSet介绍https://blog.csdn.net/BinField/article/details/145898264其中Text菜单中的TTS & Morse可用于将文本转换…

【C++】编码传输:创建零拷贝帧对象4:shared_ptr转unique_ptr给到rtp打包

【C++】编码传输:创建零拷贝帧对象3: dll api转换内部的共享内存根本原因 你想要的是基于 packet 指向的那个已有对象,拷贝(或移动)出一个新的 VideoDataPacket3 实例,因此需要把那个对象本身传进去——也就是 *packet。copilot的原因分析与gpt一致 The issue is with t…

基于UDP的套接字通信

udp是一个面向无连接的&#xff0c;不安全的&#xff0c;报式传输层协议&#xff0c;udp的通信过程默认也是阻塞的。使用UDP进行通信&#xff0c;服务器和客户端的处理步骤比TCP要简单很多&#xff0c;并且两端是对等的 &#xff08;通信的处理流程几乎是一样的&#xff09;&am…

华为CE交换机抓包

capture-packet interface 100GE1/0/5 destination file 001.cap packet-len 64 注&#xff1a;早期版本&#xff08;disp device&#xff09;可能在系统视图下&#xff08;sys&#xff09; 抓完包后可以看到对应文件&#xff08;早期版本在根目录下&#xff09;&#xff1a;…

Python 数据分析与可视化 Day 3 - Pandas 数据筛选与排序操作

&#x1f3af; 今日目标 掌握 DataFrame 的条件筛选&#xff08;布尔索引&#xff09;学会多条件筛选、逻辑运算熟练使用排序&#xff08;sort_values&#xff09;提升数据组织力结合列选择进行数据提取分析 &#x1f9ea; 一、列选择与基本筛选 ✅ 选择单列 / 多列 df[&quo…

Vite项目初始化与配置

下面,我们来系统的梳理关于 Vite 项目初始化与配置 的基本知识点: 一、Vite 核心概念与优势 1.1 什么是 Vite? Vite(法语意为 “快速”)是新一代的前端构建工具,由 Vue.js 作者尤雨溪开发。它解决了传统构建工具(如 Webpack)在开发环境中的性能瓶颈问题。 1.2 Vite …

Transformer中的核心问题 知识点汇总

Transformer架构图 transformer整体架构 1. Transformer 的参数配置 Transformer 的Encoder层和Decoder层都使用6个注意力模块&#xff0c;所有的子网络的输出维度均为512维&#xff0c;多头注意力部分使用了8个注意力头。 2. 归一化的方式 归一化的方式为LayerNorm&#xff0c…

python web开发-Flask数据库集成

Flask 数据库集成完全指南&#xff1a;Flask-SQLAlchemy 实践 1. 引言 数据库是现代Web应用的核心组件&#xff0c;Flask通过Flask-SQLAlchemy扩展提供了强大的数据库集成能力。本文将全面介绍如何在Flask应用中使用Flask-SQLAlchemy进行数据库操作&#xff0c;涵盖从基础配置…

一站式用AI编程神奇Cursor/Trae(VScode环境)开发运行Scala应用

平时开发时&#xff0c;我们常用 IDEA 搭配 Scala 来开发 Spark 或 Flink 等大数据应用。但如今像 Cursor 这样的编程神器层出不穷&#xff0c;它们只支持 VSCode。要是 Scala 应用能在 VSCode 环境下便捷运行&#xff0c;我们就无需在 VSCode 开发、却在 IDEA 运行&#xff0c…

【Django开发】django美多商城项目完整开发4.0第2篇:项目准备,配置【附代码文档】

教程总体简介&#xff1a;美多商城 商业模式介绍 1.B2B--企业对企业 2.C2C--个人对个人 5.O2O--线上到线下 开发流程 说明&#xff1a; 需求分析 1. 用户部分 注册 登录 个人信息 地址管理 修改密码 3. 购物车部分 购物车管理 项目架构 创建工程 1. 在git平台创建工程 2. 添加前…

基于 OpenCV 的图像亮度、对比度与锐度调节

图像亮度、对比度和锐度是图像质量感知的重要参数&#xff0c;调节这些属性常用于图像增强、图像美化或图像分析的预处理阶段。本文将基于 OpenCV 实现这三项基础图像处理功能&#xff0c;并提供滑动条交互界面与直方图可视化分析&#xff0c;方便调试和理解效果。 亮度调整 图…

WAF(web应用防火墙)的简单了解

WAF称之为Web应用防火墙&#xff0c;是一种专门设计用于保护web应用程序免受恶意攻击的安全设备&#xff0c;能实时监控过滤和拦截可能对网站造成危害的网络流量&#xff0c;从而避免网络服务器被恶意入侵导致性能异常、数据泄露、服务中断这些问题 (WAF是通过执行一系列针对HT…

跟着AI学习C# Day28

&#x1f4c5; Day 28&#xff1a;C# 源生成器&#xff08;Source Generators&#xff09;与编译时元编程 ✅ 学习目标&#xff1a; 理解什么是 源生成器&#xff08;Source Generator&#xff09;&#xff1b;掌握如何在 编译阶段生成 C# 代码&#xff0c;而不是运行时动态处…

设计模式精讲 Day 4:建造者模式(Builder Pattern)

【设计模式精讲 Day 4】建造者模式&#xff08;Builder Pattern&#xff09; 文章简述&#xff1a; 在软件开发中&#xff0c;对象的构造过程往往复杂且容易出错&#xff0c;尤其是在对象包含多个可选参数或构建步骤时。建造者模式&#xff08;Builder Pattern&#xff09;正是…

如何轻松地将联系人从 iPhone 转移到 iPhone?

也许您升级到最新的 iPhone 型号&#xff0c;或者需要切换到另一部 iPhone 来工作。无论如何&#xff0c;您不能错过您的联系人&#xff0c;这对每个人来说都是最重要的数据。因此&#xff0c;今天我们将分享 5 种如何将联系人从 iPhone 转移到 iPhone 的方法&#xff0c;帮助您…

【51单片机简单的流水灯程序问题】2022-5-24

1.利用单片机的P2口接8个发光二极管。简单的流水灯程序问题-编程语言-CSDN问答 2&#xff0e;发光二极管自由闪烁&#xff08;自己设计两种模式&#xff09;。 3&#xff0e;可通过按键实现暂停、启动以及不用模式的切换。 4. 利用Proteus绘制电路原理图 5. 元件选型&#xff1…