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等属性。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容

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