react-native transform-origin实现

image.png

最近在做RN项目的时候,有一个旋转效果需要指定非元素中心的原点。我们都知道在CSS3里进行transform变换的时候,默认的变换原点是元素的中心位置,css3提供了transform-origin属性来设置变换原点,但是在RN里,我翻遍了官方文档和一些源码都没有看到可以在设置类似transform-origin东西,但是RN的transform支持 matrix。

一个使用矩阵实现缩放的栗子

将图片旋转放大2倍,我们用matrix实现

export default class App extends Component {
  render() {
    return (
      <View style={styles.container}>
          <Image style={[
            styles.imageBox,
            {transform: [{matrix: [
                2, 0, 0, 0,
                0, 2, 0, 0,
                0, 0, 1, 0,
                0, 0, 0, 1]}]}
            ]} 
            source={{uri: 'http://www.google.cn/landing/cnexp/google-search.png'}} />
      </View>
    );
  }
}

这个时候的效果就和使用scale(2) 一毛一样。

顺便提一下,话说在transform的matrix属性是在rn的某个版本中才加入的,更老的版本使用的是 transformMatrix 属性,它与transform平级。

指定变换中心(transform-origin)

这里主要说明transform-origin的实现原理。其实transform-origin在css规范里面也有具体的说明。

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.

也就是如下这幅图,出自这里

css规范中的表述

翻译一下就是,要想指定变换原点,其实只需要先把元素的中心平移到变换原点,然后开始变换,完了过后再反向平移到原来的位置。

说得这么晦涩,什么变换啥的,其实矩阵变换对应到数学上就是进行矩阵乘法,不知道基础的同学建议先看看相关的知识,线性代数、基本图形变换之类的。

demo

代码在这里, 可在线预览, 有可能需要科学上网才能访问到。
下面选取了部分关键代码说明一下


    // 旋转中心
    const transformOrigin = [50, -50];
    const translate = [
       1, 0, 0, 0,
       0, 1, 0, 0,
       0, 0, 1, 0,
       transformOrigin[0], transformOrigin[1], 0, 1
      ];
    const unUseTranslate = [
       1, 0, 0, 0,
       0, 1, 0, 0,
       0, 0, 1, 0,
       -transformOrigin[0], -transformOrigin[1], 0, 1
      ];
    const a = Math.PI/6;
    const rotateMatrix = [
       Math.cos(a), Math.sin(a), 0, 0,
      -Math.sin(a), Math.cos(a), 0, 0,
       0,            0,          1, 0,
       0,            0,          0, 1
      ];
    
    // 结果矩阵
    // 先平移到旋转中心,再旋转
    let m = Matrix.multMatrix(translate, rotateMatrix);
    
    // 再平移回去
    m = Matrix.multMatrix(m, unUseTranslate);
    
    this.setState({
      matrix: m
    });

图片(容器)大小为100*100,我们如果要设置变换中心为图片的右上角的话,那么需要的旋转中心应该是 transformOrigin = [50, -50]; 这里为什么是[50, -50]呢?而不是像css属性里的是transform-origin: 100px, 0。 这是因为进行矩阵变换的时候,所应用的坐标系是元素的本地坐标系(local coordinate space),图片的中心是0,0, x轴向右为正,y轴向下为正。所以此时图片的右上角所对应的坐标是(50, -50).如下图

local coordinate space

结语

我这代码中的矩阵操作全是手动撸的,矩阵变换本来就是个麻烦而且枯燥的工作,所以如果大家在实际项目中需要用到各种矩阵操作的话,可以推荐 gl-matrix 这个库。react-native项目里面的话,可以直接使用 MatrixMath 模块。
如果深究一下css 的transform 文档,其实会发现所有的变换都可以用矩阵来表示,比如perspectiveperspective-origin等属性。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 关于css3变形 CSS3变形是一些效果的集合,比如平移、旋转、缩放和倾斜效果,每个效果都被称作为变形函数(Tra...
    hopevow阅读 6,414评论 2 13
  • 看了很多视频、文章,最后却通通忘记了,别人的知识依旧是别人的,自己却什么都没获得。此系列文章旨在加深自己的印象,因...
    DCbryant阅读 1,896评论 0 4
  • Transform字面上就是变形,改变的意思。在CSS3中transform主要包括以下几种:旋转rotate、扭...
    hzrWeber阅读 22,187评论 0 19
  • CSS里transform变形这个属性有点学习难度,尤其在CSS3里加上了3D效果之后,2维变3维学习成本更是成倍...
    张歆琳阅读 28,026评论 5 81
  • 偶然在一篇曹将的公众号上看到了印象笔记APP的介绍,第一时间就下载尝试。然而发现并没有掌握这个应用的精髓,于是乎,...
    嘟嘟陈者阅读 390评论 0 0