Transform变换

Transform可以在其子Widget绘制时对其应用一个矩阵变换(transformation),Matrix4是一个4D矩阵,通过它我们可以实现各种矩阵操作。下面是一个例子:

  1. Container(
  2. color: Colors.black,
  3. child: new Transform(
  4. alignment: Alignment.topRight, //相对于坐标系原点的对齐方式
  5. transform: new Matrix4.skewY(0.3), //沿Y轴倾斜0.3弧度
  6. child: new Container(
  7. padding: const EdgeInsets.all(8.0),
  8. color: Colors.deepOrange,
  9. child: const Text('Apartment for rent!'),
  10. ),
  11. ),
  12. );

image-20180910160248494

关于矩阵变换的相关内容属于线性代数范畴,本书不做讨论,读者有兴趣可以自行了解。本书中,我们把焦点放在Flutter中一些常见的变换效果上。

平移

Transform.translate接收一个offset参数,可以在绘制时沿x、y轴对子widget平移指定的距离。

  1. DecoratedBox(
  2. decoration:BoxDecoration(color: Colors.red),
  3. //默认原点为左上角,左移20像素,向上平移5像素
  4. child: Transform.translate(offset: Offset(-20.0, -5.0),
  5. child: Text("Hello world"),
  6. ),
  7. )

效果:

image-20180910161953078

旋转

Transform.rotate可以对子widget进行旋转变换,如:

  1. DecoratedBox(
  2. decoration:BoxDecoration(color: Colors.red),
  3. child: Transform.rotate(
  4. //旋转90度
  5. angle:math.pi/2 ,
  6. child: Text("Hello world"),
  7. ),
  8. );

注意:要使用math.pi需先进行如下导包。

  1. import 'dart:math' as math;

效果:

image-20180910162408030

缩放

Transform.scale可以对子Widget进行缩小或放大,如:

  1. DecoratedBox(
  2. decoration:BoxDecoration(color: Colors.red),
  3. child: Transform.scale(
  4. scale: 1.5, //放大到1.5倍
  5. child: Text("Hello world")
  6. )
  7. );

效果:

image-20180910162817059

注意

  • Transform的变换是应用在绘制阶段,而并不是应用在布局(layout)阶段,所以无论对子widget应用何种变化,其占用空间的大小和在屏幕上的位置都是固定不变的,因为这些是在布局阶段就确定的。下面我们距离说明:

    1. Row(
    2. mainAxisAlignment: MainAxisAlignment.center,
    3. children: <Widget>[
    4. DecoratedBox(
    5. decoration:BoxDecoration(color: Colors.red),
    6. child: Transform.scale(scale: 1.5,
    7. child: Text("Hello world")
    8. )
    9. ),
    10. Text("你好", style: TextStyle(color: Colors.green, fontSize: 18.0),)
    11. ],
    12. )

    显示效果:

    image-20180910164454967

    由于第一个Text应用变换(放大)后,其在绘制时会放大,但其占用的空间依然为红色部分,所以第二个text会紧挨着红色部分,最终就会出现文字有重合部分。

  • 由于矩阵变化只会作用在绘制阶段,所以在某些场景下,在UI需要变化时,可以直接通过矩阵变化来达到视觉上的UI改变,而不需要去重新触发build流程,这样会节省layout的开销,所以性能会比较好。如之前介绍的Flow widget,它内部就是用矩阵变换来更新UI,除此之外,Flutter的动画widget中也大量使用了Transform以提高性能。

RotatedBox

RotatedBox和Transform.rotate功能相似,它们都可以对子widget进行旋转变换,但是有一点不同:RotatedBox的变换是在layout阶段,会影响在子widget的位置和大小。我们将上面介绍Transform.rotate时的示例改一下:

  1. Row(
  2. mainAxisAlignment: MainAxisAlignment.center,
  3. children: <Widget>[
  4. DecoratedBox(
  5. decoration: BoxDecoration(color: Colors.red),
  6. //将Transform.rotate换成RotatedBox
  7. child: RotatedBox(
  8. quarterTurns: 1, //旋转90度(1/4圈)
  9. child: Text("Hello world"),
  10. ),
  11. ),
  12. Text("你好", style: TextStyle(color: Colors.green, fontSize: 18.0),)
  13. ],
  14. ),

效果:

image-20180910170603964

由于RotatedBox是作用于layout阶段,所以widget会旋转90度(而不只是绘制的内容),decoration会作用到widget所占用的实际空间上,所以就是上图的效果。读者可以和前面Transform.rotate示例对比理解。