在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);
以左边缘的开门效果如下:
相关参考资料: