RN 实现门开合动画

2,910 阅读2分钟

在CSS3中,我们可以通过设置元素:

{ 
  perspective: 1200px; 
  transform-style: preserve-3d;    
  transform: rotateY(45deg);   
  transform-origin: left;
}

来实现一个以左边缘,门开合的变换效果。

在上述代码中,我们设置了旋转的中心为元素的左边。我们知道在CSS3中进行transform变换的时候,默认的变换原点是元素的中心位置,并且CSS3也提供了transfor-origin来变更原点。但是在React Native的官方文档,或查阅相关源码,并没有找到可以设置类似origin的属性。但是在上一篇Transform在RN中的应用中,我们知道在RN是支持matrix的。

    在transform-origin的css规范的Example 4中,演示了一个元素以top:50px;left:50px为变换原点旋转45度。

div {
  height: 100px; width: 100px;
  transform-origin: 50px 50px;
  transform: rotate(45deg);
}

The transform-origin property moves the point of origin by 50 pixels in both the X and Y directions. The transform rotates the element clockwise by 45° about the point of origin. After all transform functions were applied, the translation of the origin gets translated back by -50 pixels in both the X and Y directions.

从这边我们可以看到,指定元素的变换原点,其实是先把元素移动到我们想要的变换原点,然后开始做变换,变换后再反向将元素移动到原来的位置。如上述例子,先把元素移动到50px 50px的位置,旋转,然后再反向移动-50px -50px的位置。

那么,回到我们本文的中心,如何实现一个门的开合状态?

以下截取关键代码:

    import MatrixMath from 'react-native/Libraries/Utilities/MatrixMath';

    const halfWidth = this.width / 2; // 门宽度的一半    
    const halfHeight = this.height / 2; // 门高度一半
    let x = 0;
    let y = 0; 
    let degree = radians * (Math.PI / 180); // 旋转的角度
    switch (origin) {
      case Direction.top:
        y = -halfHeight;
        break;
      case Direction.bottom:
        y = halfHeight;
        break; 
     case Direction.left:
        x = -halfWidth;
        break;
      case Direction.right: 
       x = halfWidth;
        break;
      default:
        break; 
   }    
   const moveTo = MatrixMath.createIdentityMatrix(); 
   const moveReverse = MatrixMath.createCopy(moveTo);
   const rotate = MatrixMath.createCopy(moveTo);
   MatrixMath.reusePerspectiveCommand(moveTo, 900); // 透视位置
   // 先移动到中心点    
   MatrixMath.reuseTranslate3dCommand(moveTo, x, y, 0);
   // 旋转动画,这边可通过传入是以“上/下边缘”还是“左右边缘”来做开合
   if (origin === Direction.top || origin === Direction.bottom) {
      MatrixMath.reuseRotateXCommand(rotate, degree);    
   } else {     
    MatrixMath.reuseRotateYCommand(rotate, degree);   
   }   
   // 再返回到原来的位置
   MatrixMath.reuseTranslate3dCommand(moveReverse, -x, -y, 0); 
   // 平移到变换原点,然后旋转
   MatrixMath.multiplyInto(out, moveTo, rotate); 
   // 反向回去
   MatrixMath.multiplyInto(out, out, moveReverse);

以左边缘的开门效果如下:

相关参考资料:

transform-origin的css规范

Transform: matrix在react native的使用