如何实现唱片机指针摆动动画效果
===============

#### 问题现象

如何实现如下效果：页面中包含播放按钮和指针图片，当点击播放时，指针图片逆时针偏移，当点击暂停时，指针图片恢复至原来位置。

#### 背景知识

*   UIContext提供[animateTo](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-uicontext-uicontext#animateto)接口来指定由于闭包代码导致的状态变化插入过渡动效。
*   [rotate](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-universal-attributes-transformation#rotate)是HarmonyOS提供的一种通用属性，用于设置组件旋转效果。

#### 解决方案

1.  给需要添加动画的组件添加rotate属性，设置组件的旋转角度。
    
    .rotate({ angle: this.rotateAngle, centerX: 30, centerY: 100 }); _// 图片旋转属性_
    
2.  在animateTo显式动画的闭包函数中判断当前打开状态，设置旋转角度。
    
    _// 显式动画执行，逆时针旋转30度_
    this.getUIContext().animateTo({
      duration: 800,
      curve: Curve.Friction,
      delay: 300,
      iterations: 1, _// 设置-1表示动画无限循环_
      playMode: PlayMode.Alternate,
      expectedFrameRateRange: {
        min: 20,
        max: 120,
        expected: 90,
      }
    }, () => {
      if (this.flag) {
        this.rotateAngle = -30;
      } else {
        this.rotateAngle = 0;
      }
    });
    
    完整示例参考如下：
    
    @Entry
    @Component
    struct AttrAnimationExample {
      @State rotateAngle: number = 0; _// 旋转弧度_
      @State flag: boolean = false; _// 是否播放_
    
      build() {
        Column() {
          Stack() {
            Row() {
              Text('唱片机内容').fontSize(16);
            }
            .width('100%')
            .height(200)
            .backgroundColor('#87CEEB')
            .justifyContent(FlexAlign.Center);
    
            Row() {
              Image($r('app.media.startIcon')) _// 此处仅为样例，请开发者更换为可用图片_
                .width(60)
                .height(100)
                .rotate({ angle: this.rotateAngle, centerX: 30, centerY: 100 }); _// 图片旋转属性_
            }
            .alignItems(VerticalAlign.Bottom)
            .width('100%')
            .justifyContent(FlexAlign.End)
            .height(200);
          };
    
        _  // 播放/暂停按钮_
          Button(this.flag ? '暂停' : '播放').onClick(() => {
            this.flag = !this.flag;
         _   // 显式动画执行，逆时针旋转30度_
            this.getUIContext().animateTo({
              duration: 800,
              curve: Curve.Friction,
              delay: 300,
              iterations: 1, _// 设置-1表示动画无限循环_
              playMode: PlayMode.Alternate,
              expectedFrameRateRange: {
                min: 20,
                max: 120,
                expected: 90,
              }
            }, () => {
              if (this.flag) {
                this.rotateAngle = -30;
              } else {
                this.rotateAngle = 0;
              }
            });
          })
            .margin({ top: 40 });
        }
        .padding({ left: 12, right: 12 })
        .height('100%')
        .width('100%');
      }
    }