1/* 2 * Copyright (c) 2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15import { window, KeyboardAvoidMode } from '@kit.ArkUI'; 16import { inputMethod } from '@kit.IMEKit'; 17import { KeyboardDataSource } from '../basicDataResource/BasicDataSource'; 18import { common } from '@kit.AbilityKit'; 19 20/** 21 * 功能描述: 本示例介绍使用TextInput组件和LazyForEach实现组件随软键盘弹出避让场景 22 * 23 * 推荐场景: 需要用户手动输入文字的场景 24 * 25 * 核心组件: 26 * 1. KeyboardAvoid.liftUpComponents 27 * 2. KeyboardAvoid.scalingComponents 28 * 29 * 实现步骤: 30 * 1. 在输入按钮的点击事件中调用focusControl.requestFocus API,即可实现给TextInput组件申请焦点功能 31 * 2. 通过监听键盘高度,可以感知到键盘的拉起收起状态,实现缩放组件尺寸的调整,配合KeyboardAvoidMode.RESIZE避让模式,实现组件上抬压缩效果 32 */ 33@Component 34export struct KeyboardAvoid { 35 @State keyboardHeight: number = 0; // 软键盘高度 36 @State contentData: string[] = 37 ['第一条数据', '第二条数据', '第三条数据', '第四条数据', '第五条数据', '第六条数据', '第七条数据', '第八条数据', 38 '第九条数据', '第十条数据', '第十一条数据', '第十二条数据']; 39 @State isLiftUpShow: boolean = true; 40 @State isScalingShow: boolean = false; 41 @StorageLink('avoidAreaBottomToModule') avoidAreaBottomToModule: number = 0; 42 private scrollerForLiftUp: Scroller = new Scroller(); 43 private scrollerForScaling: Scroller = new Scroller(); 44 private dataSource: KeyboardDataSource = new KeyboardDataSource(this.contentData); 45 46 aboutToAppear(): void { 47 // TODO:知识点:虚拟键盘抬起时,页面的避让模式设置为RESIZE模式 48 let context = getContext(this) as common.UIAbilityContext; 49 context.windowStage.getMainWindowSync().getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.RESIZE); 50 window.getLastWindow(getContext(this)).then(currentWindow => { 51 currentWindow.on('keyboardHeightChange', (data: number) => { 52 this.keyboardHeight = px2vp(data); 53 }) 54 }) 55 } 56 57 // 上抬组件 58 @Builder 59 liftUpComponents() { 60 Scroll(this.scrollerForLiftUp) { 61 Column() { 62 LazyForEach(this.dataSource, (item: string) => { 63 this.liftUpContentComponent(item) 64 }, (item: string) => item) 65 } 66 .id('KeyboardAvoidLiftUpComponents') 67 .width($r('app.string.key_board_components_weight')) 68 .alignItems(HorizontalAlign.Center) 69 .justifyContent(FlexAlign.End) 70 .backgroundColor($r('app.color.key_board_page_background_color')) 71 } 72 .height($r('app.string.key_board_lift_up_components_height')) 73 .layoutWeight(1) 74 .visibility(this.isLiftUpShow ? Visibility.Visible : Visibility.None) 75 .borderRadius($r('app.string.key_board_scenes_main_page_list_borderRadius')) 76 } 77 78 // 上抬组件成员 79 @Builder 80 liftUpContentComponent(item: string) { 81 Row() { 82 Image('') 83 .borderRadius($r('app.string.key_board_scenes_item_image_border_radius')) 84 .objectFit(ImageFit.Contain) 85 .width($r('app.string.key_board_scenes_item_image_height')) 86 .height($r('app.string.key_board_scenes_item_image_height')) 87 .backgroundColor($r('app.color.key_board_item_image_background_color')) 88 .margin($r('app.string.key_board_scenes_item_image_border_radius')) 89 Text(item) 90 .padding({ 91 left: $r('app.string.key_board_scenes_main_page_padding6'), 92 right: $r('app.string.key_board_scenes_main_page_padding6') 93 }) 94 .width($r('app.string.key_board_components_weight')) 95 .textAlign(TextAlign.Start) 96 .maxLines(2) 97 .fontSize($r('app.string.key_board_scenes_item_text_font_size')) 98 .fontColor($r('app.color.key_board_item_font_color')) 99 .margin({ 100 top: $r('app.string.key_board_scenes_main_page_margin_top'), 101 bottom: $r('app.string.key_board_scenes_main_page_margin_top') 102 }) 103 .textOverflow({ overflow: TextOverflow.Ellipsis }) 104 } 105 .linearGradient({ 106 angle: 180, 107 colors: [[$r('app.color.key_board_item_background_color1'), 0], 108 [$r('app.color.key_board_item_background_color2'), 1]] 109 }) 110 .width($r('app.string.key_board_components_weight')) 111 .borderRadius($r('app.string.key_board_scenes_main_page_list_borderRadius')) 112 .margin($r('app.string.key_board_scenes_item_gap_half')) 113 } 114 115 // 缩放组件 116 @Builder 117 scalingComponents() { 118 Scroll(this.scrollerForScaling) { 119 Column() { 120 Grid() { 121 LazyForEach(this.dataSource, (item: string) => { 122 GridItem() { 123 this.scalingContentComponent(item) 124 } 125 }, (item: string) => item) 126 } 127 .backgroundColor($r('app.color.key_board_page_background_color')) 128 .cachedCount(Number($r('app.integer.key_board_grid_cache_count'))) 129 } 130 .id('KeyboardAvoidScalingComponents') 131 .width($r('app.string.key_board_components_weight')) 132 .alignItems(HorizontalAlign.Center) 133 .justifyContent(FlexAlign.End) 134 } 135 .height($r('app.string.key_board_lift_up_components_height')) 136 .layoutWeight(1) 137 .visibility(this.isScalingShow ? Visibility.Visible : Visibility.None) 138 .borderRadius($r('app.string.key_board_scenes_main_page_list_borderRadius')) 139 } 140 141 // 缩放组件成员 142 @Builder 143 scalingContentComponent(item: string) { 144 Column() { 145 Image('') 146 .borderRadius(8) 147 .objectFit(ImageFit.Contain) 148 .width(this.keyboardHeight > 0 ? $r('app.string.key_board_scenes_item_small_image_height') : 149 $r('app.string.key_board_scenes_item_big_image_height')) 150 .height(this.keyboardHeight > 0 ? $r('app.string.key_board_scenes_item_small_image_height') : 151 $r('app.string.key_board_scenes_item_big_image_height')) 152 .backgroundColor($r('app.color.key_board_item_image_background_color')) 153 .margin($r('app.string.key_board_scenes_item_gap_half')) 154 Text(item) 155 .fontColor(Color.Black) 156 .textAlign(TextAlign.Center) 157 .fontSize($r('app.string.key_board_scenes_item_text_font_size')) 158 .fontColor($r('app.color.key_board_item_font_color')) 159 .margin({ 160 top: $r('app.string.key_board_scenes_main_page_margin_top'), 161 bottom: $r('app.string.key_board_scenes_main_page_margin_top') 162 }) 163 .textOverflow({ overflow: TextOverflow.Ellipsis }) 164 } 165 .linearGradient({ 166 angle: 180, 167 colors: [[$r('app.color.key_board_item_background_color1'), 0], 168 [$r('app.color.key_board_item_background_color2'), 1]] 169 }) 170 .alignItems(HorizontalAlign.Center) 171 .justifyContent(FlexAlign.Center) 172 .width(this.keyboardHeight > 0 ? $r('app.string.key_board_scenes_item_small_height') : 173 $r('app.string.key_board_scenes_item_big_height')) 174 .height(this.keyboardHeight > 0 ? $r('app.string.key_board_scenes_item_small_height') : 175 $r('app.string.key_board_scenes_item_big_height')) 176 .borderRadius($r('app.string.key_board_scenes_main_page_list_borderRadius')) 177 .margin($r('app.string.key_board_scenes_item_gap_half')) 178 } 179 180 build() { 181 Column() { 182 this.liftUpComponents() 183 this.scalingComponents() 184 TextInput()// TODO:知识点:输入框自动获焦 185 .id('keyboardAvoidTextInput') 186 .defaultFocus(true) 187 .key($r('app.string.key_board_text_input_key_string').toString()) 188 .border({ 189 width: $r('app.integer.key_board_text_input_border_width'), 190 color: $r('app.color.key_board_input_border_color') 191 }) 192 .opacity($r('app.string.key_board_scenes_item_image_opacity')) 193 .margin($r('app.integer.key_board_scenes_tab_bar_image_more_row_margin')) 194 Row() { 195 Button($r('app.string.key_board_button_input_string')) 196 .id('KeyboardAvoidButtonPopUpKeyboard') 197 .opacity(this.keyboardHeight > 0 ? 0.5 : 1) 198 .onClick(() => { 199 // TODO:知识点:使用focusControl.requestFocus API实现textInput获焦拉起键盘 200 focusControl.requestFocus($r('app.string.key_board_text_input_key_string').toString()); 201 }) 202 Button($r('app.string.key_board_button_lift_up_string')) 203 .id('KeyboardAvoidButtonLiftUp') 204 .fontColor(this.isLiftUpShow ? Color.White : Color.Black) 205 .backgroundColor(this.isLiftUpShow ? $r('app.color.key_board_button_selected_color') : 206 $r('app.color.key_board_button_unselected_color')) 207 .opacity(this.isLiftUpShow ? 1 : 0.8) 208 .onClick(() => { 209 // 点击按钮实现上抬组件显示,缩放组件隐藏 210 this.isLiftUpShow = true; 211 this.isScalingShow = false; 212 }) 213 Button($r('app.string.key_board_button_scaling_string')) 214 .id('KeyboardAvoidButtonScaling') 215 .fontColor(this.isScalingShow ? Color.White : Color.Black) 216 .backgroundColor(this.isScalingShow ? $r('app.color.key_board_button_selected_color') : 217 $r('app.color.key_board_button_unselected_color')) 218 .opacity(this.isScalingShow ? 1 : 0.8) 219 .onClick(() => { 220 // 点击按钮实现缩放组件显示,上抬组件隐藏 221 this.isScalingShow = true; 222 this.isLiftUpShow = false; 223 }) 224 } 225 .justifyContent(FlexAlign.SpaceAround) 226 .width($r('app.string.key_board_components_weight')) 227 } 228 .id('KeyboardAvoidBlank') 229 .padding({ bottom: px2vp(this.avoidAreaBottomToModule) }) 230 .width($r('app.string.key_board_components_weight')) 231 .height($r('app.string.key_board_components_height')) 232 .onClick(() => { 233 // 点击收起键盘 234 inputMethod.getController().stopInputSession(); 235 }) 236 } 237}