• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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}