Flutter(59):Layout组件之Transform

1.Transform介绍

可以在其子组件绘制前对其应用一些矩阵变换来实现一些特效。
这里需要注意的是这种变换特效是应用在绘制阶段而不是布局阶段,也就是说子控件虽然进行了变换,但是他所占用的实际空间,位置等都是固定不变的,只是视觉上改变了。

2.Transform.rotate

  • angle:旋转弧度 注意这里不是角度,需要将角度转为弧度,180度 = π弧度 即1度=π/180 弧度
  • origin:以某一个原点旋转,这个是相对于alignment位置所设置的Offset的偏移点为原点旋转
  • alignment = Alignment.center:以alignment位置为原点旋转
  • child:
    关于Alignment之前已经介绍过了:Flutter(44):Layout组件之Container

这里的旋转内部实现是Matrix4.rotationZ(angle)变换,即以Z轴为旋转轴旋转angle弧度
我们来看个例子:

  _myChild() {
    return Text(
      'Hello Flutter',
      style: TextStyle(
        backgroundColor: Colors.blue,
        fontSize: 20,
        color: Colors.white,
      ),
    );
  }

  _myTransformRotate() {
    return Stack(
      children: [
        Center(
          child: _myChild(),
        ),
        Center(
          child: Transform.rotate(
            angle: dartMath.pi * 0.25,
            alignment: Alignment.center,
            child: _myChild(),
          ),
        ),
        Center(
          child: Transform.rotate(
            angle: dartMath.pi * 0.25,
            origin: Offset(50, 50),
            alignment: Alignment.center,
            child: _myChild(),
          ),
        ),
        Center(
          child: Transform.rotate(
            angle: dartMath.pi * 0.25,
            alignment: null,
            child: _myChild(),
          ),
        ),
      ],
    );
  }

这里我们分别有四个“Hello Flutter”,第一个不做任何变换;第二个设置Alignment.center为原点旋转45度,即以控件的中心点旋转45度;第三个是以Alignment.center偏移Offset(50, 50)的点为原点旋转15度,即以控件的中心点,向右偏移50,向下偏移50的一个点为原点旋转45度;第四个就是设置alignment旋转45度,即以控件的Alignment.topLeft(左上角)为原点旋转45度。

  • Stack组件,它是一个多子节点组件,支持叠放子控件,这个组件后面我们会详细介绍。
  • dartMath其实是导入的dart中的math
import 'dart:math' as dartMath;
image.png

3.Transform.translate

  • offset:Offset 偏移位置
  • child:

这里就是平移变换到原位置的Offset位置,内部实现是Matrix4.translationValues(offset.dx, offset.dy, 0.0)变换

  _myTransformTranslate() {
    return Stack(
      children: [
        Center(
          child: Transform.translate(
            offset: Offset(0, 0),
            child: _myChild(),
          ),
        ),
        Center(
          child: Transform.translate(
            offset: Offset(50, 50),
            child: _myChild(),
          ),
        ),
      ],
    );
  }

这里就是将“Hello Flutter”相对于原来位置向右平移50向下平移50

image.png

4.Transform.scale

  • scale:缩放系数
  • origin:以某一个原点缩放,这个是相对于alignment位置所设置的Offset的偏移点为原点缩放
  • alignment = Alignment.center:以alignment位置为原点缩放
  • child:

这里的缩放内部实现是Matrix4.diagonal3Values(scale, scale, 1.0)变换

  _myTransformScale() {
    return Stack(
      children: [
        Center(
          child: Transform.scale(
            scale: 2,
            origin: Offset(50, 50),
            alignment: Alignment.center,
            child: _myChild(),
          ),
        ),
        Center(
          child: Transform.scale(
            scale: 2,
            alignment: Alignment.center,
            child: _myChild(),
          ),
        ),
        Center(
          child: Transform.scale(
            scale: 1,
            alignment: Alignment.center,
            child: _myChild(),
          ),
        ),
      ],
    );
  }

这里呢我们从下往上看,最后一个就是以Alignment.center为原点缩放一倍,即维持原样;倒数第二个就是以Alignment.center为原点放大两倍;倒数第三个也就是第一个是以Alignment.center向左偏移50,向下偏移50的位置为原点放大两倍

image.png

5.Transform

  • transform:Matrix4
  • origin:相对于alignment的偏移原点
  • alignment:alignment
  • child:

前面几种的变化其实都是基于Matrix4进行的变换,那么如果以上三种无法满足需求还有一种就是由你自己去设置transform变换

例如我们这里想实现一个以中心点为原点,X轴为旋转轴旋转180的变换

  _myTransform(Matrix4 transform) {
    return Center(
      child: Transform(
        transform: transform,
        alignment: Alignment.center,
        child: _myChild(),
      ),
    );
  }

      body: _myTransform(Matrix4.rotationX(dartMath.pi * 0.75)),
image.png

6.Matrix4

Matrix4还提供了非常之多的矩阵变换,例如沿Y轴旋转,沿X扭曲,沿Y轴扭曲,还支持复合。我们这里简单介绍一些:

平移
  • Matrix4.translationValues(double x, double y, double z)
    x代表X轴,大于0向右,小于0向左;y代表Y轴,大于0向下,小于0向上;z代表Z轴,大于0凸起,小于0下凹,但是这个在这种平面图上是显示不出来效果的。
  • Matrix4.translation(Vector3 translation)
    这种方式是使用向量的方式,需要import 'package:vector_math/vector_math_64.dart',
    Vector3(double x, double y, double z),跟第一种本质没区别。
body: _myTransform(Matrix4.translationValues(-50, 20, 0)),
body: _myTransform(Matrix4.translation(vectorMath.Vector3(-50, 20, 0))),
body: _myTransform(
    Matrix4.translation(vectorMath.Vector3.array([-50, 20, 0]))),
image.png
旋转
  • Matrix4.rotationX(double radians)
    X轴旋转,旋转弧度大于0就是由Y轴正方向向Z轴正方向旋转,小于0就是Z轴正方向向Y轴正方向旋转
body: _myTransform(Matrix4.rotationX(dartMath.pi * 0.25)),
image.png
  • Matrix4.rotationY(double radians)
    沿Y轴旋转,旋转弧度大于0就是由X轴正方向向Z轴正方向旋转,小于0就是Z轴正方向向X轴正方向旋转
body: _myTransform(Matrix4.rotationY(dartMath.pi * 0.25)),
image.png
  • Matrix4.rotationZ(double radians)
    沿Z轴旋转,旋转弧度大于0就是由Y轴正方向向X轴正方向旋转,小于0就是X轴正方向向Y轴正方向旋转
body: _myTransform(Matrix4.rotationZ(dartMath.pi * 0.25)),
image.png
缩放
  • Matrix4.diagonal3(Vector3(double x, double y, double z))
  • Matrix4.diagonal3Values(double x, double y, double z)
    这里的值表示缩放的比例,分别沿x,y,z三个方向,x轴正向向右,y轴正向向下,z轴正向从屏幕朝上,正值表示正向,>1表示放大,小于1大于0表示缩小,负值表示反向,会翻转。
body: _myTransform(Matrix4.diagonal3(vectorMath.Vector3(2, -0.8, 0))),
image.png
扭曲
  • Matrix4.skewX(double alpha)
    沿X轴扭曲
body: _myTransform(Matrix4.skewX(dartMath.pi * 0.25)),
image.png
  • Matrix4.skewY(double beta)
    沿Y轴扭曲
body: _myTransform(Matrix4.skewY(dartMath.pi * 0.25)),
image.png
  • Matrix4.skew(double alpha, double beta)
body: _myTransform(Matrix4.skew(dartMath.pi * 0.2,dartMath.pi * 0.1)),
image.png

其他还有使用矩阵创建,取反(inverted),合并(outer),复合(compose)这些都些矩阵变换都需要对线性代数有了解了,这里就不说了。

7.验证Transform变换是在绘制阶段而不是在布局阶段

  _myRow() {
    return Center(
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Transform.scale(
            scale: 2,
            alignment: Alignment.center,
            child: _myChild(),
          ),
          _myChild()
        ],
      ),
    );
  }
image.png

这里可以看到前一个“Hello Flutter”放大后并没有影响后面一个的位置,由此也可以看出变换是绘制阶段而不是在布局阶段。这种矩阵变换的优点就是发生在绘制阶段,他不需要去重新布局或者构建,对性能上很友好。

下一节:Layout组件之UnconstrainedBox

Flutter(60):Layout组件之UnconstrainedBox

Flutter教学目录持续更新中

Github源代码持续更新中

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