HarmonyOS鸿蒙Next中json动画用啥方便一点

HarmonyOS鸿蒙Next中json动画用啥方便一点

5 回复

开发者你好,加载json动画可以使用lottie三方库。

【背景知识】 [@ohos/lottie](https://ohpm.openharmony.cn/#/cn/detail/@ohos%2Flottie)提供了使用JSON动画文件的解决方案,具有一套完整的API控制动画的行为,可以让动画更具有交互性。

【解决方案】

参考点赞弹出动画实现:

  1. 通过overlay构建中间图片
  2. 通过isLiked来控制点击之后图标颜色的切换的效果。
  3. 通过lottie三方库加载json动画,在动画完成一次之后销毁页面的动画。

参考示例代码:

import lottie, { AnimationItem } from '[@ohos](/user/ohos)/lottie';
@Entry
@Component
export struct Page25051301 {
  private renderingSettings: RenderingContextSettings = new RenderingContextSettings(true)
  private canvasRenderingContext: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.renderingSettings)
  private mainRenderingSettings: RenderingContextSettings = new RenderingContextSettings(true)
  private mainCanvasRenderingContext: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.mainRenderingSettings)
  private animateItem: AnimationItem | null = null;
  private mianItem: AnimationItem | null = null;
  @State imageSrcList: ResourceStr = $r('app.media.like')
  // 未点赞时的颜色(灰色)
  @State unlikeColor: string = '#757575'
  // 点赞后的颜色(蓝色)
  @State likeColor: string = '#ff4eb1e6'
  // 是否已点赞状态
  @State isLiked: boolean = false
  // 控制Image组件和Canvas的切换
  @State isVisibility:boolean=true
  // 防止动画过程中点去除颜色
  @State isFlag:boolean=false
  // 第一个canvas动画的名称
  @State animateName:string='animateName'
  // 第二个canvas动画的名称
  @State mainNme:string='mainNme'
  // 控制图片显示和隐藏
  @State visibilityType:Visibility=Visibility.Visible
  onPageHide(): void {
    lottie.destroy()
  }
  @Builder
  OverlayNode() {
      Canvas(this.mainCanvasRenderingContext)
        .width(200)
        .aspectRatio(1)
        .onReady(() => {
          this.mianItem?.resize();
        })
  }
  build() {
    Column() {
      Stack({alignContent:Alignment.Center}) {
        Image(this.imageSrcList)
          .width(100+'px')
          .aspectRatio(1)
          .fillColor(this.isLiked ? this.likeColor : this.unlikeColor)// 图片要求svg格式
          .visibility(this.isVisibility?Visibility.Visible:Visibility.None)
         Column() {
           Canvas(this.canvasRenderingContext)
             .width(100)
             .aspectRatio(1)
             .backgroundColor(Color.Transparent)
             .onReady(() => {
               this.animateItem?.resize();
             })
         }
      }
      .onClick(()=>{
        // 防止动画过程中填充色的消除
        if(this.isFlag) return
        // 点击时切换点赞状态
        this.isLiked = !this.isLiked
        if(this.isLiked)  {
          this.isVisibility=false
          this.onLoadAnimation()
          this.mianOnLoadAnimation()
        }
      })
      .width(200)
      .height(200)
    }
    .overlay(this.OverlayNode(), { align: Alignment.Center })
    .width('100%')
    .height('100%')
    .backgroundColor('#f1f1f1')
  }
   // 点赞动图加载
   onLoadAnimation() {
     lottie.destroy(this.animateName)
     this.isFlag=true
     this.animateItem = lottie.loadAnimation({
       container: this.canvasRenderingContext,  // 渲染上下文
       renderer: 'canvas', // canvas 渲染模式
       loop:true,
       name: this.animateName,
       frameRate: 30,
       contentMode: 'Cover',
       path: "lottie/like.json", // 路径加载动画只支持entry/src/main/ets 文件夹下的相对路径
     })
     // 监听完成一次动画
     this.animateItem.addEventListener('loopComplete', (args: Object): void => {
       if( this.animateItem?.playCount==1) {
         lottie.destroy(this.animateName)
         this.isVisibility=true
         this.isFlag=false
       }
     });
  }
  mianOnLoadAnimation() {
    lottie.destroy(this.mainNme)
    this.mianItem = lottie.loadAnimation({
      container: this.mainCanvasRenderingContext,  // 渲染上下文
      renderer: 'canvas', // canvas 渲染模式
      autoplay: true,
      loop:true,
      name: this.mainNme,
      frameRate: 30,
      contentMode: 'Contain',
      path: "lottie/like.json", // 路径加载动画只支持entry/src/main/ets 文件夹下的相对路径
    })
    // 监听完成一次动画
    this.mianItem.addEventListener('loopComplete', (args: Object): void => {
      if( this.mianItem?.playCount==1) {
        lottie.destroy(this.mainNme)
      }
    });
  }
}

更多关于HarmonyOS鸿蒙Next中json动画用啥方便一点的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


JSON 动画一版都采用 Lottie 动画库,能高效实现复杂动画效果且开发便!!

步骤一:先通过命令 ohpm install @ohos/lottie 安装。再添加 Lottie 依赖:

"dependencies": {
  "[@ohos](/user/ohos)/lottie": "2.0.20"
}

步骤二:将 JSON动画 文件放置在项目目录下

步骤三:通过 Canvas 组件绑定 Lottie 动画:

Canvas(this.canvasContext)
  .onReady(() => {
    lottie.loadAnimation({
      container: this.canvasContext, // 绑定画布
      renderer: 'canvas',
      loop: true,
      autoplay: true,
      path: 'common/lottie/animation.json' // 第二步你放置的JSON 文件路径
    });
  })

Lottie

库地址

[https://ohpm.openharmony.cn/#/cn/detail/@ohos%2Flottie](https://ohpm.openharmony.cn/#/cn/detail/@ohos%2Flottie)

import lottie, { AnimationItem } from '[@ohos](/user/ohos)/lottie';

@Entry
@Component
struct Index {
  // 构建上下文
  private renderingSettings: RenderingContextSettings = new RenderingContextSettings(true);
  private canvasRenderingContext: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.renderingSettings);
  private animateItem: AnimationItem | null = null;
  private animateName: string = 'animation'; 

  // 页面销毁时释放动画资源
  aboutToDisappear(): void {
    console.info('aboutToDisappear');
    lottie.destroy();
  }

  build() {
    Row() {
      // 关联画布
      Canvas(this.canvasRenderingContext)
        .width(200)
        .height(200)
        .backgroundColor(Color.Gray)
        .onReady(() => {
          // 加载动画
          if (this.animateItem != null) {
            // 可在此生命回调周期中加载动画,可以保证动画尺寸正确
            this.animateItem?.resize();
          } else {
            // 抗锯齿的设置
            this.canvasRenderingContext.imageSmoothingEnabled = true;
            this.canvasRenderingContext.imageSmoothingQuality = 'medium';
            this.loadAnimation();
          }
        })
    }
  }

  loadAnimation() {
    this.animateItem = lottie.loadAnimation({
      container: this.canvasRenderingContext,
      renderer: 'canvas', // canvas 渲染模式
      loop: true,
      autoplay: false,
      name: this.animateName,
      contentMode: 'Contain',
      path: 'common/animation.json',
    })
    // 因为动画是异步加载,所以对animateItem的操作需要放在动画加载完成回调里操作
    this.animateItem.addEventListener('DOMLoaded', (args: Object): void => {
      this.animateItem.changeColor([225, 25, 100, 1]);
      this.animateItem.play();
    });
  }

  destroy() {
    this.animateItem.removeEventListener('DOMLoaded');
    lottie.destroy(this.animateName);
    this.animateItem = null;
  }
}

在HarmonyOS Next中,推荐使用Lottie或SVGA实现JSON动画。Lottie通过解析JSON格式的Bodymovin文件高效渲染矢量动画,SVGA则支持跨平台高性能动画播放。两者均兼容鸿蒙的ArkUI框架,可直接在组件中调用,无需依赖Java或C语言。

在HarmonyOS Next中,推荐使用Lottie库来处理JSON动画。Lottie支持解析和渲染由After Effects导出的JSON动画文件,集成简单且性能优秀。可以通过ohpm安装lottie-ohos包,并直接加载JSON文件实现流畅动画效果。

回到顶部