flutter3.0学习笔记

Transform\Matrix4

Preview
  • Transform
  • Vector3
  • Matrix4矩阵变换

Transform

Transform组件可以对子组件进行变化,比如旋转、平移、缩放等。

  • 构造函数
const Transform({
    super.key,
    required this.transform,//Matrix4对象
    this.origin,//是一个Offset对象
    this.alignment,//是origin的对其方式,是一个AlignmentGeometry对象
    this.transformHitTests = true,//点击区域是否也做相应的变换,为true时执行相应的变换,为false不执行
    this.filterQuality,//图像的取样质量
    super.child,
  })
  • 基本用法:
Transform(
  transform: Matrix4.rotationZ(0.5),//绕z轴旋转弧度
  //origin参数表示变换矩阵的坐标,默认是(0,0)即左上角,如果想围绕圆心旋转
  origin: const Offset(50,50),
  child: Container(
    width: 100,
    height: 100,
    color: Colors.green,
  ),
)

Transform为方便调用构建了Transform.translateTransform.rotateTransform.scale

  • Transform.translate 构造函数
Transform.translate({
    super.key,
    required Offset offset,
    this.transformHitTests = true,
    this.filterQuality,
    super.child,
  }) 

用法:

Transform.translate(
  offset: const Offset(50.0,100.0),
  child: Container(
    width: 100,
    height: 100,
    color: Colors.blue,
  )
),
  • Transform.rotate 构造函数:
Transform.rotate({
    super.key,
    required double angle,
    this.origin,
    this.alignment = Alignment.center,
    this.transformHitTests = true,
    this.filterQuality,
    super.child,
  }) 

用法:

 Transform.rotate(
   angle: pi/4,//pi/4,也就是45度
  child: Container(
    width: 100,
    height: 100,
    color: Colors.amber,
  ),
)
  • Transform.scale 构造函数:
 Transform.scale({
    super.key,
    double? scale,//整体缩放
    double? scaleX,//宽度缩放
    double? scaleY,//高度缩放
    this.origin,
    this.alignment = Alignment.center,
    this.transformHitTests = true,
    this.filterQuality,
    super.child,
  })

用法:

Transform.scale(
  //scale: 1.5,
   scaleX: 1.5,
   scaleY: 1,
   child: Container(
     width: 100,
     height: 100,
     color: Colors.red,
   ),
)

效果: Simulator Screen Shot - iPhone 14 Pro - 2022-12-12 at 17.56.57.png

Vector3

Vector 是向量,矢量的意思,向量既有大小,又有方向,Verctor3 就是三维向量,一个三维向量会有三个分量,分别是 x,y,z。

Verctor3类在flutter中有两种构造方法,三个参数分别对应x/y/z轴方向缩放。

factory Vector3(double x, double y, double z) =>
   new Vector3.zero()..setValues(x, y, z);

factory Vector3.array(List<double> array, [int offset = 0]) =>
  new Vector3.zero()..copyFromArray(array, offset);

使用Vector3,我们需要引入vector_math_64包,这个是flutter自带的,不需要我们去安装

import 'package:vector_math/vector_math_64.dart' as vector;

注意:vector_math和vector_math_64应该是针对32bit和64bit变体的,它们在包中作为两个不同的库实现。因此,需要在使用这些库的方式上保持一致性。

 export 'package:vector_math/vector_math_64.dart'
  或者
 export 'package:vector_math/vector_math.dart'

Matrix4矩阵变换

Matrix4是一个4D矩阵,通过它我们可以实现各种矩阵操作。

  • 构造
Matrix4(double arg0, … double arg15)

Matrix4 默认构造函数由 16 个参数,从左到右从上到下依此排列为一个四阶矩阵;

Matrix4(
   1.0, 0.0, 0.0, 0.0, 
   0.0, 1.0, 0.0, 0.0, 
   0.0, 0.0, 1.0, 0.0, 
   0.0, 0.0, 0.0, 1.0
)
  • Matrix4.identity()(初始化)

Matrix4.identity() 会初始化一个如上的 Matrix4,可在此基础上进行其他矩阵操作;

 Transform(
      transform: Matrix4.identity()..rotateZ(pi/16),
      origin: const Offset(100,50),//旋转点
      child: Container(
        width: 200,
        height: 100,
        color: Colors.green,
        child: const Center(child: Text('Matrix4.identity'),),
      ),
    )

image.png

- Matrix4.zero()(置零矩阵)

Matrix4.zero() 会初始化一个所有参数值为 0 的空矩阵,在此基础上设置具体的变化矩阵:

Transform(
 transform: Matrix4.zero()..setIdentity()..rotateZ(pi/16),
 origin: const Offset(100,50),//旋转点
 child: Container(
   width: 200,
   height: 100,
   color: Colors.green,
   child: const Center(child: Text('Matrix4.zero'),),
 ),
),

image.png

  • Matrix4.fromList()

将一个16位的一维数组转换成4*4的矩阵, Matrix4.fromList() 将 List 列表中数据赋值进入 ,Matrix4(double arg0, … double arg15)

List<double> list = [
    1.0, 0.0, 0.0, 0.0, 
    0.0, 1.0, 0.0, 0.0, 
    0.0, 0.0, 1.0, 0.0, 
    0.0, 0.0, 0.0, 1.0
];
  ....
   Transform(
      transform: Matrix4.fromList(list)..rotateZ(pi/16),
      origin: const Offset(100,50),//旋转点
      child: Container(
        width: 200,
        height: 100,
        color: Colors.green,
        child: const Center(child: Text('Matrix4.fromList'),),
      ),
    ),

image.png

  • Matrix4.copy()(复制)

Matrix4.copy() 拷贝一个已有的 Matrix4

 Transform(
 //copy:复制一个4*4的矩阵
  // transform: Matrix4.copy(Matrix4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)),
  transform: Matrix4.copy(Matrix4.identity()),//同上都是复制一个4*4的矩阵
 origin: const Offset(100,50),//旋转点
 child: Container(
   width: 200,
   height: 100,
   color: Colors.green,
   child: const Center(child: Text('Matrix4.copy'),),
 ),
),
  • Matrix4.columns()

设置一个新的矩阵,Matrix4.columns() 由四个 4D 列向量组成。

 transform: Matrix4.columns(
    vector.Vector4(1.0,0.0,0.0,0.0),
    vector.Vector4(0.0,1.0,0.0,0.0),
    vector.Vector4(0.0,0.0,1.0,0.0),
    vector.Vector4(0.0,0.0,0.0,1.0),
 ),
  • Matirx4.inverted()

Matrix4.inverted() 为逆向矩阵,与原 Matrix4 矩阵相反(矩阵坐标沿着左对角线对称)

 Transform(
  transform: Matrix4.inverted(Matrix4.fromList(list)..rotateZ(pi/16)),
  origin: const Offset(100,50),//旋转点
  child: Container(
    width: 200,
    height: 100,
    color: Colors.green,
    child: const Center(child: Text('Matrix4.inverted'),),
  ),
),

image.png

  • Matrix4.outer()(合并)

Matrix4.outer() 为两个四阶矩阵的合并乘积,注意两个四阶矩阵的先后顺序决定最终合并后的矩阵数组:

transform: Matrix4.outer(v.Vector4(1.0, 1.0, 1.0, 1.20), v.Vector4.identity()),
transform: Matrix4.outer(v.Vector4.identity(), v.Vector4(1.0, 1.0, 1.0, 1.20)),
  • Matrix4.diagonal3()(缩放)

Matrix4.diagonal3() 通过 Vector3 设置缩放矩阵:

 Transform(
  transform: Matrix4.diagonal3(vector.Vector3(1.5,1.0,1.0)),
  origin: const Offset(100,50),//旋转点
  child: Container(
    width: 200,
    height: 100,
    color: Colors.green,
    child: const Center(child: Text('Matrix4.diagonal3'),),
  ),
),
const SizedBox(height: 10,),
Transform(
  transform: Matrix4.diagonal3(vector.Vector3.array([0.5,0.5,0.5])),
  origin: const Offset(100,50),//旋转点
  child: Container(
    width: 200,
    height: 100,
    color: Colors.green,
    child: const Center(child: Text('Matrix4.diagonal3'),),
  ),
),

image.png

  • Matirx4.diagonal3Values()(缩放)

Matrix4.diagonal3Values() 类似于将上述构造方法提取出来,直接对三个参数进行缩放赋值:

 Transform(
      transform: Matrix4.diagonal3Values(1.5,1.0,1.0),
      origin: const Offset(100,50),//旋转点
      child: Container(
        width: 200,
        height: 100,
        color: Colors.green,
        child: const Center(child: Text('Matrix4.diagonal3Values'),),
      ),
    ),
    const SizedBox(height: 10,),
    Transform(
      transform: Matrix4.diagonal3Values(0.5,0.5,0.5),
      origin: const Offset(100,50),//旋转点
      child: Container(
        width: 200,
        height: 100,
        color: Colors.green,
        child: const Center(child: Text('Matrix4.diagonal3Values'),),
      ),
    ),

image.png

  • Matrix4.translation()(平移)

Matrix4.translation 同样通过 Vector3 构造方法的各参数设置矩阵平移量;水平向右为 x 轴正向,竖直向下为 y 轴正向:

 Row(
      mainAxisAlignment: MainAxisAlignment.spaceAround,
      children: [
        Transform(
          transform: Matrix4.translation(vector.Vector3(10.0,10.0,10.0)),
          child: Container(
            width: 150,
            height: 50,
            color: Colors.green,
            child: const Center(child: Text('Matrix4.translation'),),
          ),
        ),
        Transform(
          transform: Matrix4.translation(vector.Vector3.array([-10.0,-10.0,-10.0])),
          child: Container(
            width: 150,
            height: 50,
            color: Colors.green,
            child: const Center(child: Text('Matrix4.translation'),),
          ),
        ),
      ],
    )

image.png

  • Matrix4.translationValues()(平移)

Matrix4.translationValues() 将矩阵平移量直接赋值展示,效果同上Matrix4.translation()

Row(
      mainAxisAlignment: MainAxisAlignment.spaceAround,
      children: [
        Transform(
          transform: Matrix4.translationValues(10.0,10.0,10.0),
          child: Container(
            width: 150,
            height: 50,
            color: Colors.green,
            child: const Center(child: Text('Matrix4.translation'),),
          ),
        ),
        Transform(
          transform: Matrix4.translationValues(-10.0,-10.0,-10.0),
          child: Container(
            width: 150,
            height: 50,
            color: Colors.green,
            child: const Center(child: Text('Matrix4.translation'),),
          ),
        ),
      ],
    )
  • Matrix4.rotationX()(沿 x 轴方向旋转)
 Row(
      mainAxisAlignment: MainAxisAlignment.spaceAround,
      children: [
        Transform(
          transform: Matrix4.rotationX(pi/3),
          origin: const Offset(100,100),//旋转点
          child: Container(
            width: 100,
            height: 100,
            color: Colors.green,
            child: const Center(child: Text('Matrix4.rotationX'),),
          ),
        ),

        Transform(
          transform: Matrix4.rotationX(pi/6),
          origin: const Offset(100,100),//旋转点
          child: Container(
            width: 100,
            height: 100,
            color: Colors.green,
            child: const Center(child: Text('Matrix4.rotationX'),),
          ),
        ),

      ],
    )

image.png

  • Matrix4.rotationY()(沿 y 轴方向旋转)
Row(
      mainAxisAlignment: MainAxisAlignment.spaceAround,
      children: [
        Transform(
          transform: Matrix4.rotationY(pi/3),
          origin: const Offset(100,100),//旋转点
          child: Container(
            width: 100,
            height: 100,
            color: Colors.green,
            child: const Center(child: Text('Matrix4.rotationY'),),
          ),
        ),

        Transform(
          transform: Matrix4.rotationY(pi/6),
          origin: const Offset(100,100),//旋转点
          child: Container(
            width: 100,
            height: 100,
            color: Colors.green,
            child: const Center(child: Text('Matrix4.rotationY'),),
          ),
        ),

      ],
    )

image.png

  • Matrix4.rotationZ()(沿 z 轴方向旋转)
 Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Transform(
          transform: Matrix4.rotationZ(0),
          origin: const Offset(50,50),//旋转点
          child: Container(
            width: 100,
            height: 100,
            color: Colors.green,
            child: const Center(child: Text('Matrix4.rotationZ'),),
          ),
        ),

        Transform(
          transform: Matrix4.rotationZ(45),
          origin: const Offset(50,50),//旋转点
          child: Container(
            width: 100,
            height: 100,
            color: Colors.green,
            child: const Center(child: Text('Matrix4.rotationZ'),),
          ),
        ),

      ],
    )

image.png

  • Matrix4.skewX()(skewX() 是沿 x 轴方向斜切)
Row(
      mainAxisAlignment: MainAxisAlignment.spaceAround,
      children: [
        Transform(
          transform: Matrix4.skewX(0),
          child: Container(
            width: 100,
            height: 100,
            color: Colors.green,
            child: const Center(child: Text('skewX'),),
          ),
        ),

        Transform(
          transform: Matrix4.skewX(pi/6),
          child: Container(
            width: 100,
            height: 100,
            color: Colors.green,
            child: const Center(child: Text('skewX'),),
          ),
        ),

      ],
    ),

image.png

  • Matrix4.skewY()(沿 y 轴方向斜切)
 Row(
  mainAxisAlignment: MainAxisAlignment.spaceAround,
  children: [
    Transform(
      transform: Matrix4.skewY(0),
      child: Container(
        width: 100,
        height: 100,
        color: Colors.green,
        child: const Center(child: Text('skewY'),),
      ),
    ),

    Transform(
      transform: Matrix4.skewY(pi/6),
      child: Container(
        width: 100,
        height: 100,
        color: Colors.green,
        child: const Center(child: Text('skewY'),),
      ),
    ),

  ],
),

image.png

  • Matrix4.skew()(沿 x / y 轴方向斜切)
Row(
  mainAxisAlignment: MainAxisAlignment.center,
  children: [
    Transform(
      transform: Matrix4.skew(0,0),
      child: Container(
        width: 100,
        height: 100,
        color: Colors.green,
        child: const Center(child: Text('skew'),),
      ),
    ),
    const SizedBox(width: 50,),
    Transform(
      transform: Matrix4.skew(pi/6,pi/6),
      child: Container(
        width: 100,
        height: 100,
        color: Colors.green,
        child: const Center(child: Text('skew'),),
      ),
    ),

  ],
),

image.png

  • Matrix4.compose()

Matrix4.compose()可以将平移/旋转/缩放共同组合操作。

  • 构造函数
Matrix4.compose(
  Vector3 translation, //平移
  Quaternion rotation, //旋转
  Vector3 scale //缩放
)

例子:

import 'package:flutter/material.dart';
import 'package:vector_math/vector_math_64.dart' as vector;
class Matrix4Page extends StatefulWidget {
  const Matrix4Page({Key? key}) : super(key: key);

  @override
  State<Matrix4Page> createState() => _Matrix4PageState();
}

class _Matrix4PageState extends State<Matrix4Page> with TickerProviderStateMixin {
   final Matrix4 _begin = Matrix4.compose(
      vector.Vector3(0,0,1),
      vector.Quaternion.euler(0, 0, 0),
      vector.Vector3(1,1,1)
  );
  final Matrix4 _midway = Matrix4.compose(
      vector.Vector3(0,0,1),
      vector.Quaternion.euler(1, -0.2, 0),
      vector.Vector3(.8,.8,.8)
  );

  final Matrix4 _finally = Matrix4.compose(
      vector.Vector3(0,0,1),
      vector.Quaternion.euler(1, 0, 0),
      vector.Vector3(1,1,1)
  );
   Matrix4 _end = Matrix4.compose(
      vector.Vector3(0,0,1),
      vector.Quaternion.euler(1, -0.2, 0),
      vector.Vector3(0.8,0.8,0.8)
  );

  @override
  Widget build(BuildContext context){
    return TweenAnimationBuilder(
        tween: Tween(begin: _begin,end: _end),
        duration: const Duration(seconds: 2), 
        builder: (BuildContext context,Matrix4 value,Widget? _){
          return Transform(
            transform: value,
            child: Scaffold(
              appBar: AppBar(
                title: const Text('Matrix4'),
                backgroundColor: Colors.transparent,
              ),
              body: Center(
                child: Container(
                  width: 200,
                  height: 200,
                  color: Colors.red,
                ),
              ),
              floatingActionButton: FloatingActionButton(
                onPressed: (){
                  setState(() {
                    if(_end == _begin){
                      _end = _midway;
                    }else if(_end == _midway){
                      _end = _finally;
                    }else{
                      _end = _begin;
                    }
                  });
                },
                child: const Icon(Icons.rotate_left),
              ),
            ),
          );    
        }
    );
  }
}