1# Web组件对接软键盘 2<!--Kit: ArkWeb--> 3<!--Subsystem: Web--> 4<!--Owner: @weixin_41848015--> 5<!--Designer: @libing23232323--> 6<!--Tester: @ghiker--> 7<!--Adviser: @HelloCrease--> 8 9开发者能够通过Web组件对接软键盘,来处理系统软键盘的显示与交互问题,同时实现软键盘的自定义功能。主要有以下场景: 10 11- 拉起系统软键盘输入文字:点击网页输入框时,屏幕下方将弹出系统默认的软键盘。开发者可以通过软键盘输入文字,输入的内容会显示在输入框中。 12- 自定义系统软键盘的回车键类型:设置不同的回车键类型,例如:确认、下一个和提交。 13- 软键盘避让:在移动设备上,由于输入法通常固定在屏幕下半段,应用可设置不同的Web页面软键盘避让模式,来避让软键盘。例如:平移、调整大小和不避让。 14- 自定义软键盘输入:在移动设备上,可以使用自绘制输入法在Web页面输入,以此替代系统软键盘。 15 16 17 18## Web页面输入框输入与软键盘交互的W3C标准支持 19 20为支持Web页面与系统软键盘、自定义软键盘等的良好交互,ArkWeb遵循并实现了W3C规范中的以下输入控制属性: 21- type属性 22 23 type属性定义了input元素的类型,影响输入的验证、显示方式和键盘类型。常见的type值包括: 24 25 | type值 | 描述 | 26 | -------- | ---------- | 27 | text | 默认值。普通文本输入 | 28 | number | 数字输入 | 29 | email | 电子邮件地址输入 | 30 | password | 密码输入 | 31 | tel | 电话号码输入 | 32 | url | URL输入 | 33 | date | 日期选择器 | 34 | time | 时间选择器 | 35 | checkbox | 复选框 | 36 | radio | 单选按钮 | 37 | file | 文件上传 | 38 | submit | 提交按钮 | 39 | reset | 重置按钮 | 40 | button | 普通按钮 | 41 42- inputmode属性 43 44 inputmode属性用于配置输入法类型,默认值:text。 45 46 | inputmode | 描述 | 47 | --------- | ---------------------------------------- | 48 | decimal | 只显示数字键盘,通常还有一个逗号键。 | 49 | email | 文本键盘,键通常用于电子邮件地址,如[@]。 | 50 | none | 不应出现键盘。 | 51 | numeric | 只显示数字键盘。 | 52 | search | 文本键盘,[enter]键通常显示为[go]。 | 53 | tel | 只显示数字键盘,通常还有[+]、[*]和[#]键。 | 54 | text | 默认文本键盘。 | 55 | url | 文本键盘,键通常用于网址,如[.]和[/],以及特殊的[.com]键,或者其他通常用于本地设置的域名结束符。 | 56 57- enterkeyhint属性 58 59 enterkeyhint属性用于指定移动设备虚拟键盘上回车键的显示方式。 60 61 | enterkeyhint值 | 描述 | 62 | ------------- | --------- | 63 | enter | 显示默认的回车键 | 64 | done | 表示输入完成 | 65 | go | 表示跳转或执行 | 66 | next | 进入下一个输入字段 | 67 | previous | 返回上一个输入字段 | 68 | search | 执行搜索 | 69 | send | 发送信息 | 70 71>**说明:** 72> 73>点击网页输入框时,屏幕下方将弹出系统默认的软键盘,用户可以进行文字输入。 74> 75>type属性影响键盘显示、输入验证和元素外观。 76> 77>inputmode优化移动设备键盘输入体验,不影响基本行为或验证。 78 79 80## 软键盘自动弹出 81为提升用户体验,可以在页面完成加载后,输入框自动获焦并弹出软键盘。通过调用[showTextInput()](../reference/apis-ime-kit/js-apis-inputmethod.md#showtextinput10)设置软键盘自动弹出功能。 82 83```html 84<!-- index.html --> 85<!DOCTYPE html> 86<html> 87 <head> 88 <title>测试网页</title> 89 </head> 90 <body> 91 <h1>DEMO</h1> 92 <input type="text" id="input_a"> 93 </body> 94</html> 95``` 96 97```ts 98//Index.ets 99import { webview } from '@kit.ArkWeb'; 100import { inputMethod } from '@kit.IMEKit'; 101 102@Entry 103@Component 104struct WebComponent { 105 controller: webview.WebviewController = new webview.WebviewController(); 106 build() { 107 Column() { 108 Web({ src: $rawfile("index.html"), controller: this.controller}) 109 .onPageEnd(() => { 110 this.controller.runJavaScript(`document.getElementById('input_a').focus()`).then(() => { 111 setTimeout(() => { 112 inputMethod.getController().showTextInput(); 113 }, 10); 114 }); 115 }); 116 } 117 } 118} 119``` 120 121## 设置软键盘避让模式 122 123在移动设备上,支持设置Web页面的软键盘避让模式。 124 1251. 在应用代码中设置UIContext的软键盘避让模式[setKeyboardAvoidMode()](../reference/apis-arkui/arkui-ts/ts-universal-attributes-expand-safe-area.md#setkeyboardavoidmode11)。ArkWeb组件支持Resize和Offset两种模式。 126 127- Resize模式下,应用窗口高度可缩小避开软键盘,ArkWeb组件跟随ArkUI重新布局。 128- Offset模式下(以及默认模式),应用窗口高度不变,ArkWeb组件根据自身的避让模式进行避让。 129 130(1)设置UIContext的软键盘避让模式。 131 132```ts 133// EntryAbility.ets 134import { KeyboardAvoidMode } from '@kit.ArkUI'; 135import { hilog } from '@kit.PerformanceAnalysisKit'; 136 137onWindowStageCreate(windowStage: window.WindowStage) { 138 hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); 139 140 windowStage.loadContent('pages/Index', (err, data) => { 141 let keyboardAvoidMode = windowStage.getMainWindowSync().getUIContext().getKeyboardAvoidMode(); 142 // 设置虚拟键盘抬起时压缩页面大小为减去键盘的高度 143 windowStage.getMainWindowSync().getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.RESIZE); 144 if (err.code) { 145 hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); 146 return; 147 } 148 hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); 149 }); 150} 151``` 152(2)在Web组件中调起软键盘。 153 154```html 155<!-- index.html --> 156<!DOCTYPE html> 157<html> 158 <head> 159 <title>测试网页</title> 160 </head> 161 <body> 162 <h1>DEMO</h1> 163 <input type="text" id="input_a"> 164 </body> 165</html> 166``` 167 168```ts 169//Index.ets 170import { webview } from '@kit.ArkWeb'; 171 172@Entry 173@Component 174struct KeyboardAvoidExample { 175 controller: webview.WebviewController = new webview.WebviewController(); 176 build() { 177 Column() { 178 Row().height("50%").width("100%").backgroundColor(Color.Gray) 179 Web({ src: $rawfile("index.html"),controller: this.controller}) 180 Text("I can see the bottom of the page").width("100%").textAlign(TextAlign.Center).backgroundColor(Color.Pink).layoutWeight(1) 181 }.width('100%').height("100%") 182 } 183} 184``` 185ArkWeb组件将跟随ArkUI重新布局,效果如图1和图2所示。 186 187**图1** Web组件网页默认软键盘避让模式 188 189 190 191**图2** Web组件网页跟随Arkui软键盘避让模式 192 193 194 1952.在UIContext的键盘避让模式为Offset模式时,应用可通过[WebKeyboardAvoidMode()](../reference/apis-arkweb/arkts-basic-components-web-e.md#webkeyboardavoidmode12)设置ArkWeb组件的键盘避让模式。Web组件的[WebKeyboardAvoidMode()](../reference/apis-arkweb/arkts-basic-components-web-e.md#webkeyboardavoidmode12)接口优先级高于W3C侧virtualKeyboard.overlayContens。 196 197- RESIZE_VISUAL:仅调整可视视口的大小,而不调整布局视口的大小。 198- RESIZE_CONTENT:调整视觉视口和布局视口的大小。 199- OVERLAYS_CONTENT:不调整任何视口的大小,获焦input元素没有滚动到可识区域的行为。 200 201>**说明:** 202> 203>可视视口指用户正在看到的网站的区域,该区域的宽度等于移动设备的浏览器窗口的宽度。 204> 205>布局视口指网页本身的宽度。 206 207在应用代码中设置ArkWeb的软键盘避让模式。 208 209```ts 210// Index.ets 211import { webview } from '@kit.ArkWeb'; 212 213@Entry 214@Component 215struct KeyboardAvoidExample { 216 controller: webview.WebviewController = new webview.WebviewController(); 217 build() { 218 Column() { 219 Row().height("50%").width("100%").backgroundColor(Color.Gray) 220 Web({ src: $rawfile("index.html"),controller: this.controller}) 221 .keyboardAvoidMode(WebKeyboardAvoidMode.OVERLAYS_CONTENT) //此时ArkWeb组件不会调整任何视口的大小。 222 Text("I can see the bottom of the page").width("100%").textAlign(TextAlign.Center).backgroundColor(Color.Pink).layoutWeight(1) 223 }.width('100%').height("100%") 224 } 225} 226``` 227ArkWeb组件根据避让模式进行避让,效果见图3。 228 229**图3** Web组件网页自身软键盘避让模式 230 231 232 2333.在软键盘弹出时,为使Web组件不发生避让行为,可通过调用[expandSafeArea()](../reference/apis-arkui/arkui-ts/ts-universal-attributes-expand-safe-area.md#expandsafearea)设置Web组件扩展安全区域。更多详细示例可参考[网页中安全区域计算和避让适配](../web/web-safe-area-insets.md)。 234 235 ```ts 236 // xxx.ets 237 import { webview } from '@kit.ArkWeb'; 238 239 @Entry 240 @Component 241 struct WebComponent { 242 controller: webview.WebviewController = new webview.WebviewController(); 243 244 build() { 245 Column() { 246 Web({ src: 'www.example.com', controller: this.controller }) 247 .width('100%').height('100%') 248 .expandSafeArea([SafeAreaType.KEYBOARD, SafeAreaType.SYSTEM]) 249 } 250 } 251 } 252 ``` 253 254 255与其他Web组件行为的交互场景: 256 257| 交叉场景 | 规格 | 258| ------------ | ---------------------------------------- | 259| 同层渲染 | 同层Web:软键盘避让方式与普通场景相同。<br></div>同层系统组件:由ArkUI负责软键盘避让模式。 | 260| 离屏创建组件 | 默认使用与非离屏创建一致的软键盘避让模式 在上树前设置其他避让模式可需生效。 | 261| customDialog | customDialog自身避让。 | 262| 折叠屏 | 软键盘避让行为与普通场景行为一致。软件键盘将根据屏幕开合状态进行调整。 | 263| 软键盘托管 | 软键盘避让行为与普通场景行为一致。 | 264| Web嵌套滚动 | 在嵌套滚动场景下,建议不要使用Web软键盘避让,包括RESIZE_VISUAL和RESIZE_CONTENT。 | 265 266 267 268## 拦截系统软键盘与自定义软键盘输入 269 270应用可以通过调用[onInterceptKeyboardAttach](../reference/apis-arkweb/arkts-basic-components-web-events.md#oninterceptkeyboardattach12)标签即将触发软键盘显示时,[onInterceptKeyboardAttach](../reference/apis-arkweb/arkts-basic-components-web-events.md#oninterceptkeyboardattach12)被回调。应用可以使用此接口控制软键盘的显示,包括系统默认软键盘、带有特定Enter键的软键盘,或完全自定义软键盘。借助这一功能,开发者能够实现对软键盘的灵活管理。 271 272- 使用系统默认软键盘 273- 使用带有定制Enter键的系统软键盘 274- 使用完全由应用程序自定义的软键盘 275 276```ts 277 // Index.ets 278 import { webview } from '@kit.ArkWeb'; 279 import { inputMethodEngine } from '@kit.IMEKit'; 280 281 @Entry 282 @Component 283 struct WebComponent { 284 controller: webview.WebviewController = new webview.WebviewController(); 285 webKeyboardController: WebKeyboardController = new WebKeyboardController(); 286 inputAttributeMap: Map<string, number> = new Map([ 287 ['UNSPECIFIED', inputMethodEngine.ENTER_KEY_TYPE_UNSPECIFIED], 288 ['GO', inputMethodEngine.ENTER_KEY_TYPE_GO], 289 ['SEARCH', inputMethodEngine.ENTER_KEY_TYPE_SEARCH], 290 ['SEND', inputMethodEngine.ENTER_KEY_TYPE_SEND], 291 ['NEXT', inputMethodEngine.ENTER_KEY_TYPE_NEXT], 292 ['DONE', inputMethodEngine.ENTER_KEY_TYPE_DONE], 293 ['PREVIOUS', inputMethodEngine.ENTER_KEY_TYPE_PREVIOUS] 294 ]) 295 296 /** 297 * 自定义键盘组件Builder 298 */ 299 @Builder 300 customKeyboardBuilder() { 301 // 这里实现自定义键盘组件,对接WebKeyboardController实现输入、删除、关闭等操作。 302 Row() { 303 Text("完成") 304 .fontSize(20) 305 .fontColor(Color.Blue) 306 .onClick(() => { 307 this.webKeyboardController.close(); 308 }) 309 // 插入字符。 310 Button("insertText").onClick(() => { 311 this.webKeyboardController.insertText('insert '); 312 }).margin({ 313 bottom: 200, 314 }) 315 // 从后往前删除length参数指定长度的字符。 316 Button("deleteForward").onClick(() => { 317 this.webKeyboardController.deleteForward(1); 318 }).margin({ 319 bottom: 200, 320 }) 321 // 从前往后删除length参数指定长度的字符。 322 Button("deleteBackward").onClick(() => { 323 this.webKeyboardController.deleteBackward(1); 324 }).margin({ 325 left: -220, 326 }) 327 // 插入功能按键。 328 Button("sendFunctionKey").onClick(() => { 329 this.webKeyboardController.sendFunctionKey(6); 330 }) 331 } 332 } 333 334 build() { 335 Column() { 336 Web({ src: $rawfile('index.html'), controller: this.controller }) 337 .onInterceptKeyboardAttach((KeyboardCallbackInfo) => { 338 // option初始化,默认使用系统默认键盘 339 let option: WebKeyboardOptions = { 340 useSystemKeyboard: true, 341 }; 342 if (!KeyboardCallbackInfo) { 343 return option; 344 } 345 346 // 保存WebKeyboardController,使用自定义键盘时候,需要使用该handler控制输入、删除、软键盘关闭等行为 347 this.webKeyboardController = KeyboardCallbackInfo.controller; 348 let attributes: Record<string, string> = KeyboardCallbackInfo.attributes; 349 // 遍历attributes 350 let attributeKeys = Object.keys(attributes); 351 for (let i = 0; i < attributeKeys.length; i++) { 352 console.log('WebCustomKeyboard key = ' + attributeKeys[i] + ', value = ' + attributes[attributeKeys[i]]); 353 } 354 355 if (attributes) { 356 if (attributes['data-keyboard'] == 'customKeyboard') { 357 // 根据html可编辑元素的属性,判断使用不同的软键盘,例如这里如果属性包含有data-keyboard,且值为customKeyboard,则使用自定义键盘 358 console.log('WebCustomKeyboard use custom keyboard'); 359 option.useSystemKeyboard = false; 360 // 设置自定义键盘builder 361 option.customKeyboard = () => { 362 this.customKeyboardBuilder() 363 } 364 return option; 365 } 366 367 if (attributes['keyboard-return'] != undefined) { 368 // 根据html可编辑元素的属性,判断使用不同的软键盘,例如这里如果属性包含有keyboard-return,使用系统键盘,并且指定系统软键盘enterKey类型 369 option.useSystemKeyboard = true; 370 let enterKeyType: number | undefined = this.inputAttributeMap.get(attributes['keyboard-return']); 371 if (enterKeyType != undefined) { 372 option.enterKeyType = enterKeyType; 373 } 374 return option; 375 } 376 } 377 378 return option; 379 }) 380 } 381 } 382 } 383``` 384 385```html 386<!-- index.html --> 387 <!DOCTYPE html> 388 <html> 389 390 <head> 391 <meta charset="utf-8"> 392 <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0"> 393 </head> 394 395 <body> 396 397 <p style="font-size:12px">input标签,原有默认行为:</p> 398 <input type="text" style="width: 300px; height: 20px"><br> 399 <hr style="height:2px;border-width:0;color:gray;background-color:gray"> 400 401 <p style="font-size:12px">input标签,系统键盘自定义enterKeyType属性 enter key UNSPECIFIED:</p> 402 <input type="text" keyboard-return="UNSPECIFIED" style="width: 300px; height: 20px"><br> 403 <hr style="height:2px;border-width:0;color:gray;background-color:gray"> 404 405 <p style="font-size:12px">input标签,系统键盘自定义enterKeyType属性 enter key GO:</p> 406 <input type="text" keyboard-return="GO" style="width: 300px; height: 20px"><br> 407 <hr style="height:2px;border-width:0;color:gray;background-color:gray"> 408 409 <p style="font-size:12px">input标签,系统键盘自定义enterKeyType属性 enter key SEARCH:</p> 410 <input type="text" keyboard-return="SEARCH" style="width: 300px; height: 20px"><br> 411 <hr style="height:2px;border-width:0;color:gray;background-color:gray"> 412 413 <p style="font-size:12px">input标签,系统键盘自定义enterKeyType属性 enter key SEND:</p> 414 <input type="text" keyboard-return="SEND" style="width: 300px; height: 20px"><br> 415 <hr style="height:2px;border-width:0;color:gray;background-color:gray"> 416 417 <p style="font-size:12px">input标签,系统键盘自定义enterKeyType属性 enter key NEXT:</p> 418 <input type="text" keyboard-return="NEXT" style="width: 300px; height: 20px"><br> 419 <hr style="height:2px;border-width:0;color:gray;background-color:gray"> 420 421 <p style="font-size:12px">input标签,系统键盘自定义enterKeyType属性 enter key DONE:</p> 422 <input type="text" keyboard-return="DONE" style="width: 300px; height: 20px"><br> 423 <hr style="height:2px;border-width:0;color:gray;background-color:gray"> 424 425 <p style="font-size:12px">input标签,系统键盘自定义enterKeyType属性 enter key PREVIOUS:</p> 426 <input type="text" keyboard-return="PREVIOUS" style="width: 300px; height: 20px"><br> 427 <hr style="height:2px;border-width:0;color:gray;background-color:gray"> 428 429 <p style="font-size:12px">input标签,应用自定义键盘:</p> 430 <input type="text" data-keyboard="customKeyboard" style="width: 300px; height: 20px"><br> 431 432 </body> 433 434 </html> 435``` 436 437ArkWeb自定义键盘的示例效果如图4、图5和图6所示。 438 439**图4** ArkWeb自定义键盘数字键盘 440 441 442 443**图5** ArkWeb自定义键盘字母键盘 444 445 446 447**图6** ArkWeb自定义键盘符号键盘 448 449