目录

如何使用renderFit实现自适应伸缩动画

问题现象

在animateTo动画中,给组件添加了renderFit属性后,组件宽高也没有跟随动画实时宽高变化。希望在宽度变化时,音乐+滑动条+人声这一个Row的宽度实时变化,请问该如何实现?

背景知识

解决方案

  1. 使用@State定义透明度,布局宽度,圆角大小等状态变量,这些变量在用户交互或者动画过程中会被更新,从而更新动画的显示。
  2. 在Row组件中定义Text,Slider等组件,实现音乐播放条动画。
  3. 为父组件添加renderFit属性,将该属性参数设置为RESIZE_CONTAIN,保持动画终态内容的宽高比,使内容完整显示在组件内,且与组件保持中心对齐。

完整示例参考如下:

import { curves } from '@kit.ArkUI';

@Entry
@Component
struct Index {
  @State controlViewOpacity: number = 0.5; // 透明度
  @State controlViewShow: boolean = true; // 是否展示
  @State controlViewWidth: number = 240; // 布局宽度
  @State controlViewBorderRadius: number = 0; // 布局的圆角大小
  @State controlViewPaddingLeft: number = 0; // 内边距大小
  finalControlViewWidth: number = 240; // 最终布局宽度

  build() {
    Stack() {
      Row() {
        Row() {
          Text('音乐').fontColor(Color.White)
            .fontSize(15);
          Slider({
            value: 50,
            min: 0,
            max: 100,
            style: SliderStyle.OutSet
          })
            .selectedColor('#ffcb67')
            .trackColor('#ffcb67')
            .layoutWeight(1);
          Text('人声').fontColor(Color.White)
            .fontSize(15);
        }
        .renderFit(RenderFit.RESIZE_CONTAIN) // renderFit设置宽高跟随动画实时变化
        .opacity(this.controlViewOpacity)
        .visibility(this.controlViewShow ? Visibility.Visible : Visibility.None)
        .height(30)
        .layoutWeight(1)
        .clip(true); // 伸缩时裁剪超出部分

        Image($r('app.media.startIcon')).width(30).height(30)
          .margin({ right: 10 }).onClick(() => {
          // 点击图标执行显示动画
          this.getUIContext()?.animateTo({
            duration: 5000,
            curve: curves.springMotion(0.5, 15),
            iterations: 1,
            playMode: PlayMode.Normal,

          }, () => {
            if (this.controlViewWidth === 50) {
              this.controlViewWidth = this.finalControlViewWidth;
              this.controlViewBorderRadius = 10;
              this.controlViewPaddingLeft = 10;
              this.controlViewOpacity = 1;
              this.controlViewShow = true;
            } else {
              this.controlViewWidth = 50;
              this.controlViewBorderRadius = 25;
              this.controlViewPaddingLeft = 0;
              this.controlViewOpacity = 0;
              this.controlViewShow = false;
            }

          });
        });
      }
      .renderFit(RenderFit.RESIZE_CONTAIN)
      .backgroundColor('#000')
      .justifyContent(FlexAlign.End)
      .width(this.controlViewWidth)
      .padding({ left: this.controlViewPaddingLeft, right: 0 })
      .borderRadius(this.controlViewBorderRadius)
      .height(50);
    }
    .width('100%')
    .height('100%');
  }
}