# 如何实现组件弹簧拉伸回缩动效

#### 问题现象

如何实现组件弹簧动效？即滑动时不是边缘回弹，而是组件向滑动方向放大，滑动结束后回缩。

#### 效果预览

#### 背景知识

*   PanGesture：滑动手势用于触发滑动手势事件，滑动达到最小滑动距离（默认值为5vp）时滑动手势识别成功。通过滑动手势的实时回调更新组件状态达成弹簧动效。
*   scale：设置组件缩放。通过控制组件的缩放中心点以及缩放大小实现动效。
*   animateTo：提供全局animateTo显式动画接口来指定由于闭包代码导致的状态变化插入过渡动效。

#### 解决方案

1.  给组件绑定滑动手势，设置移动和手指抬起时的回调。
2.  滑动过程中使用百分比的形式保证缩放连续性以及边界效果。
3.  滑动结束，使用onActionEnd设置滑动手势结束回调，将缩放比例设置回原大小。

示例代码参考如下：

```
@Entry
@Component
struct SpringAnimation {
  data: Array<number> = [0, 1, 2, 3, 4, 5];
  @State scaleNumber: number = 1;

  build() {
    Column({ space: 10 }) {
      // 构建内容组件
      ForEach(this.data, (index: number) => {
        Column() {
          Text('欢迎使用HarmonyOS-' + index);
        }
        .height('10%')
        .width('90%')
        .borderRadius(12)
        .backgroundColor('#f1f3f5')
        .alignItems(HorizontalAlign.Center)
        .justifyContent(FlexAlign.Center)
        .scale({ y: 1 / this.scaleNumber, centerY: 0 });
      });
    }
    .height('100%')
    .width('100%')
    .scale({ y: this.scaleNumber, centerY: 0 }) // 设置纵向拉伸以及拉伸中心点
    .gesture(
      PanGesture()
        .onActionUpdate((event) => {
          // 通过滑动距离设置拉伸倍率
          if (event.offsetX > 0 && event.offsetX < 100) {
            // 向下滑动且控制最大响应滑动距离100和最大伸缩倍率1.5
            this.scaleNumber = event.offsetX * 0.005 + 1;
          }
        })
        .onActionEnd(() => {
          // 拉伸结束后返回原大小
          this.getUIContext()?.animateTo({
            duration: 200,
            playMode: PlayMode.Normal,
          }, () => {
            this.scaleNumber = 1;
          });
        })
    );
  }
}
```