9afce6f6创建于 2025年5月7日历史提交
/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { window, KeyboardAvoidMode } from '@kit.ArkUI';
import { inputMethod } from '@kit.IMEKit';
import { KeyboardDataSource } from '../basicDataResource/BasicDataSource';
import { common } from '@kit.AbilityKit';

/**
 * 功能描述: 本示例介绍使用TextInput组件和LazyForEach实现组件随软键盘弹出避让场景
 *
 * 推荐场景: 需要用户手动输入文字的场景
 *
 * 核心组件:
 * 1. KeyboardAvoid.liftUpComponents
 * 2. KeyboardAvoid.scalingComponents
 *
 * 实现步骤:
 * 1. 在输入按钮的点击事件中调用focusControl.requestFocus API,即可实现给TextInput组件申请焦点功能
 * 2. 通过监听键盘高度,可以感知到键盘的拉起收起状态,实现缩放组件尺寸的调整,配合KeyboardAvoidMode.RESIZE避让模式,实现组件上抬压缩效果
 */
@Component
export struct KeyboardAvoid {
  @State keyboardHeight: number = 0; // 软键盘高度
  @State contentData: string[] =
    ['第一条数据', '第二条数据', '第三条数据', '第四条数据', '第五条数据', '第六条数据', '第七条数据', '第八条数据',
      '第九条数据', '第十条数据', '第十一条数据', '第十二条数据'];
  @State isLiftUpShow: boolean = true;
  @State isScalingShow: boolean = false;
  @StorageLink('avoidAreaBottomToModule') avoidAreaBottomToModule: number = 0;
  private scrollerForLiftUp: Scroller = new Scroller();
  private scrollerForScaling: Scroller = new Scroller();
  private dataSource: KeyboardDataSource = new KeyboardDataSource(this.contentData);

  aboutToAppear(): void {
    // TODO:知识点:虚拟键盘抬起时,页面的避让模式设置为RESIZE模式
    let context = getContext(this) as common.UIAbilityContext;
    context.windowStage.getMainWindowSync().getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.RESIZE);
    window.getLastWindow(getContext(this)).then(currentWindow => {
      currentWindow.on('keyboardHeightChange', (data: number) => {
        this.keyboardHeight = px2vp(data);
      })
    })
  }

  // 上抬组件
  @Builder
  liftUpComponents() {
    Scroll(this.scrollerForLiftUp) {
      Column() {
        LazyForEach(this.dataSource, (item: string) => {
          this.liftUpContentComponent(item)
        }, (item: string) => item)
      }
      .id('KeyboardAvoidLiftUpComponents')
      .width($r('app.string.key_board_components_weight'))
      .alignItems(HorizontalAlign.Center)
      .justifyContent(FlexAlign.End)
      .backgroundColor($r('app.color.key_board_page_background_color'))
    }
    .height($r('app.string.key_board_lift_up_components_height'))
    .layoutWeight(1)
    .visibility(this.isLiftUpShow ? Visibility.Visible : Visibility.None)
    .borderRadius($r('app.string.key_board_scenes_main_page_list_borderRadius'))
  }

  // 上抬组件成员
  @Builder
  liftUpContentComponent(item: string) {
    Row() {
      Image('')
        .borderRadius($r('app.string.key_board_scenes_item_image_border_radius'))
        .objectFit(ImageFit.Contain)
        .width($r('app.string.key_board_scenes_item_image_height'))
        .height($r('app.string.key_board_scenes_item_image_height'))
        .backgroundColor($r('app.color.key_board_item_image_background_color'))
        .margin($r('app.string.key_board_scenes_item_image_border_radius'))
      Text(item)
        .padding({
          left: $r('app.string.key_board_scenes_main_page_padding6'),
          right: $r('app.string.key_board_scenes_main_page_padding6')
        })
        .width($r('app.string.key_board_components_weight'))
        .textAlign(TextAlign.Start)
        .maxLines(2)
        .fontSize($r('app.string.key_board_scenes_item_text_font_size'))
        .fontColor($r('app.color.key_board_item_font_color'))
        .margin({
          top: $r('app.string.key_board_scenes_main_page_margin_top'),
          bottom: $r('app.string.key_board_scenes_main_page_margin_top')
        })
        .textOverflow({ overflow: TextOverflow.Ellipsis })
    }
    .linearGradient({
      angle: 180,
      colors: [[$r('app.color.key_board_item_background_color1'), 0],
        [$r('app.color.key_board_item_background_color2'), 1]]
    })
    .width($r('app.string.key_board_components_weight'))
    .borderRadius($r('app.string.key_board_scenes_main_page_list_borderRadius'))
    .margin($r('app.string.key_board_scenes_item_gap_half'))
  }

  // 缩放组件
  @Builder
  scalingComponents() {
    Scroll(this.scrollerForScaling) {
      Column() {
        Grid() {
          LazyForEach(this.dataSource, (item: string) => {
            GridItem() {
              this.scalingContentComponent(item)
            }
          }, (item: string) => item)
        }
        .backgroundColor($r('app.color.key_board_page_background_color'))
        .cachedCount(Number($r('app.integer.key_board_grid_cache_count')))
      }
      .id('KeyboardAvoidScalingComponents')
      .width($r('app.string.key_board_components_weight'))
      .alignItems(HorizontalAlign.Center)
      .justifyContent(FlexAlign.End)
    }
    .height($r('app.string.key_board_lift_up_components_height'))
    .layoutWeight(1)
    .visibility(this.isScalingShow ? Visibility.Visible : Visibility.None)
    .borderRadius($r('app.string.key_board_scenes_main_page_list_borderRadius'))
  }

  // 缩放组件成员
  @Builder
  scalingContentComponent(item: string) {
    Column() {
      Image('')
        .borderRadius(8)
        .objectFit(ImageFit.Contain)
        .width(this.keyboardHeight > 0 ? $r('app.string.key_board_scenes_item_small_image_height') :
        $r('app.string.key_board_scenes_item_big_image_height'))
        .height(this.keyboardHeight > 0 ? $r('app.string.key_board_scenes_item_small_image_height') :
        $r('app.string.key_board_scenes_item_big_image_height'))
        .backgroundColor($r('app.color.key_board_item_image_background_color'))
        .margin($r('app.string.key_board_scenes_item_gap_half'))
      Text(item)
        .fontColor(Color.Black)
        .textAlign(TextAlign.Center)
        .fontSize($r('app.string.key_board_scenes_item_text_font_size'))
        .fontColor($r('app.color.key_board_item_font_color'))
        .margin({
          top: $r('app.string.key_board_scenes_main_page_margin_top'),
          bottom: $r('app.string.key_board_scenes_main_page_margin_top')
        })
        .textOverflow({ overflow: TextOverflow.Ellipsis })
    }
    .linearGradient({
      angle: 180,
      colors: [[$r('app.color.key_board_item_background_color1'), 0],
        [$r('app.color.key_board_item_background_color2'), 1]]
    })
    .alignItems(HorizontalAlign.Center)
    .justifyContent(FlexAlign.Center)
    .width(this.keyboardHeight > 0 ? $r('app.string.key_board_scenes_item_small_height') :
    $r('app.string.key_board_scenes_item_big_height'))
    .height(this.keyboardHeight > 0 ? $r('app.string.key_board_scenes_item_small_height') :
    $r('app.string.key_board_scenes_item_big_height'))
    .borderRadius($r('app.string.key_board_scenes_main_page_list_borderRadius'))
    .margin($r('app.string.key_board_scenes_item_gap_half'))
  }

  build() {
    Column() {
      this.liftUpComponents()
      this.scalingComponents()
      TextInput()// TODO:知识点:输入框自动获焦
        .id('keyboardAvoidTextInput')
        .defaultFocus(true)
        .key($r('app.string.key_board_text_input_key_string').toString())
        .border({
          width: $r('app.integer.key_board_text_input_border_width'),
          color: $r('app.color.key_board_input_border_color')
        })
        .opacity($r('app.string.key_board_scenes_item_image_opacity'))
        .margin($r('app.integer.key_board_scenes_tab_bar_image_more_row_margin'))
      Row() {
        Button($r('app.string.key_board_button_input_string'))
          .id('KeyboardAvoidButtonPopUpKeyboard')
          .opacity(this.keyboardHeight > 0 ? 0.5 : 1)
          .onClick(() => {
            // TODO:知识点:使用focusControl.requestFocus API实现textInput获焦拉起键盘
            focusControl.requestFocus($r('app.string.key_board_text_input_key_string').toString());
          })
        Button($r('app.string.key_board_button_lift_up_string'))
          .id('KeyboardAvoidButtonLiftUp')
          .fontColor(this.isLiftUpShow ? Color.White : Color.Black)
          .backgroundColor(this.isLiftUpShow ? $r('app.color.key_board_button_selected_color') :
          $r('app.color.key_board_button_unselected_color'))
          .opacity(this.isLiftUpShow ? 1 : 0.8)
          .onClick(() => {
            // 点击按钮实现上抬组件显示,缩放组件隐藏
            this.isLiftUpShow = true;
            this.isScalingShow = false;
          })
        Button($r('app.string.key_board_button_scaling_string'))
          .id('KeyboardAvoidButtonScaling')
          .fontColor(this.isScalingShow ? Color.White : Color.Black)
          .backgroundColor(this.isScalingShow ? $r('app.color.key_board_button_selected_color') :
          $r('app.color.key_board_button_unselected_color'))
          .opacity(this.isScalingShow ? 1 : 0.8)
          .onClick(() => {
            // 点击按钮实现缩放组件显示,上抬组件隐藏
            this.isScalingShow = true;
            this.isLiftUpShow = false;
          })
      }
      .justifyContent(FlexAlign.SpaceAround)
      .width($r('app.string.key_board_components_weight'))
      .margin({ bottom: $r('app.integer.key_board_scenes_tab_bar_image_more_row_margin') })
    }
    .id('KeyboardAvoidBlank')
    .padding({ bottom: px2vp(this.avoidAreaBottomToModule) })
    .width($r('app.string.key_board_components_weight'))
    .height($r('app.string.key_board_components_height'))
    .onClick(() => {
      // 点击收起键盘
      inputMethod.getController().stopInputSession();
    })
  }
}