Flutter(59):Layout组件之Transform
Flutter教学目录持续更新中
Github源代码持续更新中
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.png4.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.png5.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