HarmonyOS鸿蒙Next中怎么实现一个固定宽高的组件从屏幕外缓慢移入视口内的动画过渡效果?

HarmonyOS鸿蒙Next中怎么实现一个固定宽高的组件从屏幕外缓慢移入视口内的动画过渡效果? 需要用什么技术实现?有没有可参考的示例?

13 回复

这样就OK了

更多关于HarmonyOS鸿蒙Next中怎么实现一个固定宽高的组件从屏幕外缓慢移入视口内的动画过渡效果?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


触发移动的条件和位置你自己看着设置

图片

固定宽高组件从屏幕外移入,用 translate + animateTo 最直接。不要动画 width/height,保持组件尺寸固定,只改变位移。

思路:

  1. 初始状态把 x 设置到屏幕外,比如 -300 或屏幕宽度。
  2. 组件上绑定 .translate({ x: this.offsetX })。
  3. 页面首帧后执行 animateTo,把 offsetX 改成 0。
  4. 如果需要淡入,再同时动画 opacity。

示意:

@State offsetX: number = -300

aboutToAppear() {
  setTimeout(() => {
    animateTo({ duration: 600, curve: Curve.EaseOut }, () => {
      this.offsetX = 0
    })
  }, 0)
}

组件本身写固定 width/height,动画期间只改 translate,这样布局不会被反复重排。

找HarmonyOS工作还需要会Flutter的哦,有需要Flutter教程的可以学学大地老师的教程,很不错,B站免费学的哦:https://www.bilibili.com/video/BV1S4411E7LY/?p=17

属性动画 (animation)

组件的某些通用属性变化时,可以通过属性动画实现渐变过渡效果,提升用户体验。支持的属性包括widthheightbackgroundColoropacityscalerotatetranslate等。对于改变布局类属性(如宽高)的动画,内容通常会直接跳转到最终状态,例如文字或Canvas中的内容。如果希望内容跟随宽高变化,可以使用renderFit属性进行配置。

官方文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-animatorproperty

这种“从屏幕外移入”的效果用 translate 配合 animateTo 就可以,核心是组件本身宽高保持固定,只改变位移状态。

做法是先把 offsetX 初始化为屏幕外位置,例如从左侧进入就是 -组件宽度 或更小;组件上设置 .translate({ x: this.offsetX })。页面出现后在 aboutToAppear 之后或首帧任务里调用 animateTo,把 offsetX 改成 0。

不要通过不断修改 width/height 来做入场动画,否则会影响布局测量。需要从右侧进入时,offsetX 可以设为窗口宽度;如果窗口宽度不固定,可以用 onAreaChange 或窗口尺寸接口拿到容器宽度后再启动动画。

  • 方案一:

    [@Entry](/user/Entry)
    [@Component](/user/Component)
    struct SlideInAnimation {
            @State translateX: number = -300; // 初始位置在屏幕左侧外(假设屏幕宽度足够)
    
            build() {
                    Column() {
                            // 固定宽高的组件
                            Column() {
                                    Text('Hello')
                                            .fontSize(20)
                                            .fontColor(Color.White)
                            }
                            .width(200)
                            .height(100)
                            .backgroundColor(Color.Blue)
                            .translate({ x: this.translateX, y: 0 }) // 应用水平位移
    
                            Button('移入视口')
                                    .margin({ top: 30 })
                                    .onClick(() => {
                                            // 使用 animateTo 触发动画,将组件移动到视口内(x=0)
                                            this.getUIContext().animateTo({
                                                    duration: 1000, // 动画持续1000毫秒
                                                    curve: Curve.EaseOut // 缓出曲线,使移动更自然
                                            }, () => {
                                                    this.translateX = 0;
                                            });
                                    })
                    }
                    .width('100%')
                    .height('100%')
                    .justifyContent(FlexAlign.Center)
            }
    }
    
  • 方案二:

    [@Entry](/user/Entry)
    [@Component](/user/Component)
    struct TransitionSlideIn {
            @State showComponent: boolean = false;
    
            build() {
                    Column({ space: 20 }) {
                            Button(this.showComponent ? '隐藏组件' : '显示组件')
                                    .width(200)
                                    .height(60)
                                    .onClick(() => {
                                            this.showComponent = !this.showComponent;
                                    })
    
                            if (this.showComponent) {
                                    // 固定宽高的组件
                                    Column() {
                                            Text('内容')
                                                    .fontSize(20)
                                                    .fontColor(Color.White)
                                    }
                                    .width(200)
                                    .height(100)
                                    .backgroundColor(Color.Green)
                                    .justifyContent(FlexAlign.Center)
                                    // 定义转场效果:从底部移入,持续500ms,使用缓出曲线
                                    .transition(
                                            TransitionEffect.move(TransitionEdge.BOTTOM)
                                                    .animation({ duration: 500, curve: Curve.EaseOut })
                                    )
                            }
                    }
                    .width('100%')
                    .height('100%')
                    .justifyContent(FlexAlign.Center)
            }
    }
    

    看看用哪个。

学习

使用translate属性+animateTo的方式可以实现

// 定义组件状态
@State offsetX: number = -1000; // 初始位置在屏幕左侧外
private containerWidth: number = 0; // 视口宽度
// 在布局中应用平移变换
Image($r('app.media.sample_photo'))
  .width(200)
  .height(200)
  .translate({ x: this.offsetX, y: 0 })
  .onClick(() => {
    // 点击时触发移入动画
    animateTo({
      duration: 500,       // 动画持续500毫秒
      curve: Curve.Ease   // 使用缓动曲线
    }, () => {
      this.offsetX = 0;   // 平移至视口内(x=0)
    });
  })

我不是回答了吗,没用?

没有看到任何回复,可能系统没审核通过吧

使用ArkTS的animateTo动画接口。定义组件初始位置(如translate偏移),在onAppear或点击时调用animateTo将偏移置零,并设置durationcurve。示例:.offset({ x: -200 }),动画内this.offsetX = 0。也可用transition结合onAppear实现进场动画。

在 HarmonyOS NEXT 中实现组件从屏幕外移入视口,最直接的方式是结合 translate 属性与 animateTo 显式动画,或利用 transitionanimateTo 的出场/入场过渡。以下提供两种简洁实现,重点示例固定宽高组件从左侧屏幕外缓慢移入。


方案一:基于 translate 的显式动画
组件初始化时设置 translate: { x: '-100%' },在 onAppear 中调用 animateTox 变为 0

@Entry
@Component
struct SlideIn {
  @State offsetX: number = -100

  aboutToAppear(): void {
    // 也可在 onAppear 中触发动画
  }

  build() {
    Column() {
      Row()
        .width(200)
        .height(80)
        .backgroundColor('#FF4081')
        .translate({ x: this.offsetX + '%' })
        .onAppear(() => {
          this.offsetX = 0
          animateTo({
            duration: 1000,
            curve: Curve.EaseOut,
            iterations: 1
          })
        })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

说明

  • 组件宽度固定 200,初始 translatex 设为 -100%(相对自身宽度偏移到左侧屏幕外)。
  • onAppear 时修改状态并触发 animateTo,动画时长 1000ms,使用 EaseOut 缓动。
  • 若需从右侧或其他方向进入,调整 x 百分比或使用 px 数值。

方案二:使用组件内置的 transition 过渡
在组件的 .transition() 中定义入场效果,通过父容器挂载/状态变化激活动画。

@Entry
@Component
struct SlideInTransition {
  @State show: boolean = false

  build() {
    Column() {
      if (this.show) {
        Row()
          .width(200)
          .height(80)
          .backgroundColor('#FF4081')
          .transition(
            TransitionEffect.OPACITY
              .compose(TransitionEffect.translate({ x: -200 }))
              .animation({ duration: 1000, curve: Curve.EaseOut })
          )
      }
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .onClick(() => {
      this.show = !this.show
    })
  }
}

说明

  • translate({ x: -200 }) 指定从自身宽度大小(200vp)的左侧位置移入,OPACITY 组合淡入效果。
  • 通过 if 控制组件创建与销毁,transition 自动执行定义好的动画。
  • 适合条件渲染场景(如弹窗),动画由框架自动衔接,无需手动管理偏移状态。

两种方案均能实现缓慢移入效果,选择时根据应用场景:单次触发或需要手动精细控制用方案一;组件挂载/卸载的过渡更推荐方案二。

回到顶部