ArkUI 动画衔接:一个动作结束,下一个别抢跑

举报
蓝瘦的蜕变 发表于 2026/11/02 21:42:17 2026/11/02
【摘要】 今天我们用 animateTo 的完成回调串两段动画。 很多动效看着乱,不是因为动画不够多,而是前一段还没结束,后一段已经抢着开始了。这个 Demo 只做两段:第一张卡片先滑出去,完成后第二张卡片再出现。 这个 Demo 看什么 核心在 startLinkage(): 第一段 animateTo 修改 firstDon

ArkUI 动画衔接:一个动作结束,下一个别抢跑

今天我们用 animateTo 的完成回调串两段动画。

很多动效看着乱,不是因为动画不够多,而是前一段还没结束,后一段已经抢着开始了。这个 Demo 只做两段:第一张卡片先滑出去,完成后第二张卡片再出现。

这个 Demo 看什么

核心在 startLinkage():

第一段 animateTo 修改 firstDone。等它的 onFinish 触发,再启动第二段 animateTo 修改 secondDone。

这样写的好处很直接:每段动画都有自己的起点和落点,顺序也清楚。等你以后要做更复杂的编排,再考虑抽方法或做专门的动画控制器。

如果你的页面里有“先收起、再展开”“先移动、再强调”这类动作,可以先用这种方式把顺序跑通。

完整代码

@Entry
@Component
struct ArkUIAnimationLinkageDemo {
  @State firstDone: boolean = false;
  @State secondDone: boolean = false;
  @State runningText: string = '等待开始';

  private startLinkage(): void {
    this.runningText = '第一段:卡片先滑出去';
    this.getUIContext().animateTo({
      duration: 420,
      curve: Curve.EaseInOut,
      onFinish: () => {
        this.runningText = '第二段:强调状态再出现';
        this.getUIContext().animateTo({
          duration: 360,
          curve: Curve.EaseOut,
          onFinish: () => {
            this.runningText = '两段动画已经顺序完成';
          }
        }, () => {
          this.secondDone = true;
        })
      }
    }, () => {
      this.firstDone = true;
    })
  }

  private resetLinkage(): void {
    this.getUIContext().animateTo({ duration: 260, curve: Curve.EaseInOut }, () => {
      this.firstDone = false;
      this.secondDone = false;
      this.runningText = '等待开始';
    })
  }

  @Builder
  HeaderBlock() {
    Column({ space: 8 }) {
      Text('ArkUI 动画衔接')
        .fontSize(28)
        .fontWeight(700)
        .fontColor('#111827')
      Text('一个动作结束,下一个别抢跑')
        .fontSize(16)
        .fontColor('#4B5563')
      Text('这页只看一件事:第一段 animateTo 完成以后,再在 onFinish 里启动第二段。')
        .fontSize(14)
        .fontColor('#6B7280')
        .lineHeight(22)
    }
    .width('100%')
    .alignItems(HorizontalAlign.Start)
  }

  build() {
    Scroll() {
      Column({ space: 22 }) {
        this.HeaderBlock()

        Stack({ alignContent: Alignment.Center }) {
          Column({ space: 8 }) {
            Text('第一段')
              .fontSize(14)
              .fontColor('#DBEAFE')
            Text('滑动离场')
              .fontSize(22)
              .fontWeight(700)
              .fontColor('#FFFFFF')
          }
          .width(150)
          .height(110)
          .borderRadius(20)
          .justifyContent(FlexAlign.Center)
          .backgroundColor('#2563EB')
          .translate({ x: this.firstDone ? -92 : 0, y: this.firstDone ? -18 : 0 })
          .opacity(this.firstDone ? 0.55 : 1)

          Column({ space: 8 }) {
            Text('第二段')
              .fontSize(14)
              .fontColor('#D1FAE5')
            Text('强调出现')
              .fontSize(22)
              .fontWeight(700)
              .fontColor('#FFFFFF')
          }
          .width(150)
          .height(110)
          .borderRadius(20)
          .justifyContent(FlexAlign.Center)
          .backgroundColor('#0F766E')
          .scale({ x: this.secondDone ? 1 : 0.72, y: this.secondDone ? 1 : 0.72 })
          .opacity(this.secondDone ? 1 : 0)
          .translate({ x: this.secondDone ? 76 : 0, y: this.secondDone ? 26 : 0 })
        }
        .width('100%')
        .height(220)
        .borderRadius(20)
        .backgroundColor('#F8FAFC')
        .border({ width: 1, color: '#E5E7EB' })

        Text(this.runningText)
          .width('100%')
          .padding(14)
          .borderRadius(14)
          .backgroundColor('#111827')
          .fontSize(14)
          .fontColor('#FFFFFF')
          .textAlign(TextAlign.Center)

        Row({ space: 12 }) {
          Button('顺序播放')
            .height(42)
            .fontSize(14)
            .fontColor('#FFFFFF')
            .backgroundColor('#2563EB')
            .borderRadius(21)
            .layoutWeight(1)
            .onClick(() => {
              this.startLinkage();
            })
          Button('重置')
            .height(42)
            .fontSize(14)
            .fontColor('#111827')
            .backgroundColor('#E5E7EB')
            .borderRadius(21)
            .layoutWeight(1)
            .onClick(() => {
              this.resetLinkage();
            })
        }
        .width('100%')
      }
      .width('100%')
      .padding(24)
      .alignItems(HorizontalAlign.Start)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#FFFFFF')
  }
}
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。