在HarmonyOS NEXT开发中Canvas 实现动画?

在HarmonyOS NEXT开发中Canvas 实现动画?

阅读 559
avatarAI BotBETA

在HarmonyOS NEXT开发中,你可以使用Canvas来实现动画。以下是一个基本的示例,展示了如何在Canvas上绘制一个简单的动画:

### 使用Canvas实现动画的示例

在HarmonyOS NEXT中,你可以通过不断更新Canvas的内容来实现动画效果。以下是一个简单的示例,展示如何在自定义组件中使用Canvas绘制一个移动的圆。

1. **创建自定义组件**:

   首先,你需要创建一个自定义组件,并在其中重写`onDraw`方法来绘制动画。

import ohos.aafwk.ability.AbilitySlice;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.window.PixelMap;
import ohos.bundle.IBundleManager;
import ohos.multimodalinput.event.TouchEvent;

public class AnimationComponent extends Component {

   private float circleX = 0;
   private float circleY = getHeight() / 2;
   private float speed = 5;
   private Paint paint;

   public AnimationComponent(AbilitySlice context) {
       super(context);
       paint = new Paint();
       paint.setColor(0xFFFF0000); // 设置圆的颜色为红色
       paint.setStyle(Paint.Style.FILL);
   }

   @Override
   protected void onDraw(Canvas canvas) {
       super.onDraw(canvas);
       canvas.drawCircle(circleX, circleY, 50, paint); // 绘制圆
       invalidate(); // 请求重新绘制,以实现动画效果
   }

   @Override
   public boolean onTouchEvent(TouchEvent event) {
       if (event.getAction() == TouchEvent.PRIMARY_POINT_DOWN) {
           startAnimation(); // 开始动画
       }
       return super.onTouchEvent(event);
   }

   private void startAnimation() {
       new Thread(() -> {
           while (circleX < getWidth()) {
               synchronized (this) {
                   circleX += speed;
                   postInvalidate(); // 在UI线程中请求重新绘制
                   try {
                       Thread.sleep(30); // 控制动画速度
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
               }
           }
       }).start();
   }

}


2. **在AbilitySlice中使用自定义组件**:

然后,你需要在你的`AbilitySlice`中添加这个自定义组件。

import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.DirectionalLayout;

public class MainAbilitySlice extends AbilitySlice {

   @Override
   protected void onStart(Intent intent) {
       super.onStart(intent);
       super.setUIContent(ResourceTable.Layout_ability_main);

       DirectionalLayout layout = (DirectionalLayout) findComponentById(ResourceTable.Id_layout);
       AnimationComponent animationComponent = new AnimationComponent(this);
       animationComponent.setWidth(getWidth());
       animationComponent.setHeight(getHeight());
       layout.addComponent(animationComponent);
   }

}


3. **布局文件**(可选):

如果你的动画组件是添加到布局文件中的,确保你的布局文件(如`ability_main.xml`)中有一个容器来放置你的组件。

<DirectionalLayout

   xmlns:ohos="http://schemas.huawei.com/res/ohos"
   ohos:width="match_parent"
   ohos:height="match_parent"
   ohos:orientation="vertical"
   ohos:id="$+id:layout">
   <!-- 其他组件 -->

</DirectionalLayout>

1 个回答

参考链接:https://developer.huawei.com/consumer/cn/doc/harmonyos-refere...
ArkTs的Canvas使用与webcanvas类似,相关动画实现可以移植webcanvas参考demo:

@Entry 
@Component 
struct Index { 
  private settings: RenderingContextSettings = new RenderingContextSettings(true) 
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings) 
  @State timerId: number = 0 
  @State startAngle: number = Math.PI * 0.2 + (Math.PI / 180) * 90; // 起始角度(弧度制) 
  @State endAngle: number = Math.PI * 1.8 + (Math.PI / 180) * 90; // 结束角度(弧度制) 
  lengthToAdd: number = Math.PI / 360; // 每次绘制的长度(弧度制) 
  @State currentAngle: number = 0 
  @State step: number = 1; 
  // 设置圆心坐标和半径 
  centerX = 200; 
  centerY = 200; 
  radius = 100; 
 
  aboutToAppear(): void { 
    this.currentAngle = this.startAngle 
    this.timerId = setInterval(() => { 
      if (this.step %2 == 1) { 
        this.currentAngle += this.lengthToAdd; 
        this.drawArc(); 
        if (this.currentAngle > this.endAngle) { 
          this.step++; 
          this.context.globalCompositeOperation = "destination-out"; // 修改混合模式,准备擦除 
          this.context.lineWidth = 21; // 擦除时,线更宽一些,防止有残留 
        } 
      } else { 
        this.eraseArc(); 
        this.currentAngle -= this.lengthToAdd; 
        if (this.currentAngle<= this.startAngle) { 
          this.step++; 
          this.context.globalCompositeOperation = "source-over"; // 修改混合模式,正常绘制 
          this.context.lineWidth = 20; // 正常线宽 
        } 
      } 
    }, 10) 
  } 
 
  drawArc() { 
    // 绘制圆弧 
    this.context.beginPath(); 
    this.context.arc( 
      this.centerX, // 圆弧中心的 x 坐标 
      this.centerY + 30, // 圆弧中心的 y 坐标 
      this.radius, // 圆弧的半径 
      this.currentAngle - this.lengthToAdd, // 圆弧的起始角度(弧度制) 
      this.currentAngle + this.lengthToAdd // 圆弧的结束角度(弧度制) 
    ); 
    this.context.stroke(); 
  } 
 
  eraseArc() { 
    this.context.beginPath(); 
    this.context.arc( 
      this.centerX, 
      this.centerY + 30, 
      this.radius, 
      this.currentAngle - this.lengthToAdd, 
      this.currentAngle + 2 * this.lengthToAdd // 擦除时,擦除的更宽一些,防止有残留 
    ); 
    this.context.stroke(); 
  } 
 
  build() { 
    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { 
      Canvas(this.context) 
        .width('100%') 
        .height('100%') 
        .backgroundColor('#ffff00') 
        .onReady(() => { 
          // 设置圆弧的颜色和宽度 
          this.context.strokeStyle = Color.Green; 
          this.context.lineWidth = 20; 
        }) 
    } 
    .width('100%') 
    .height('100%') 
  } 
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
logo
HarmonyOS
子站问答
访问
宣传栏