Rotaciones con Transform de Flutter (Part I)- Ejemplos
En este artículo, mostraremos algunos ejemplos de uso del Transform widget para girar o rotar otros widgets.
¡¡Y en el siguiente artículo, te pondrás a prueba con unos cuantos desafíos!!
Tabla de contenidos
Definición
Ángulo de rotación
Propiedades alignment y origin
Rotación alrededor del eje Z (en el plano XY)
• Modo 1
• Modo 2
• Antes de rotar…
• Rotar con el origen en la esquina superior izquierda
• Rotar con el origen en la esquina superior derecha
• Rotar con el origen en el centro
Rotación alrededor del eje X o del eje Y (perspectiva 3D)
• Explicación visual
• ¿Cómo conseguimos en Flutter esta vista en 3D de la figura rotada?
• Ejemplos con diferentes valores para el ángulo de rotación
• Tirar de la puerta y empujar la puerta
• Experimentando con el parámetro de perspectiva
Primero veamos algunos conceptos que nos vendrán muy bien para entender los ejemplos a lo largo del artículo.
Definición
Transform.rotate crea un widget que transforma su widget hijo usando una rotación alrededor de su centro (por defecto)
Ángulo de rotación
Nos da la magnitud medida en radianes de la rotación en sentido horario.
Propiedades alignment y origin
alignment
Controla el origen de la rotación mediante valores predefinidos: topCenter
, topLeft
, topRight
, center
, center
, center
, bottom
, topCenter
y topCenter
origin
Controla el origen de la rotación mediante valores más específicos gracias a la clase Offset
Podemos definir el origen de rotación mediante ambas propiedades, por ejemplo:
alignment: Alignment.topLeft
origin: Offset(100,50)
Rotación alrededor del eje Z (en el plano XY)
Básicamente podemos hacerlo mediante dos modos diferentes:
Modo 1
- Usar el
Transform
widget conMatrix4.rotationZ(double radians)
como valor para la propiedadtransform
:
Transform(
transform: Matrix4.rotationZ(0.3),
alignment: Alignment.topLeft,
child: Container(
color: Colors.purpleAccent,
width: 200,
height: 200,
),
)
El ángulo de rotación aparece como parámetro de
Matrix4.rotationZ(double radians)
El origen por defecto es la esquina superior izquierda del widget.
Modo 2
- Usar el constructor
Transform.rotate
:
Transform.rotate(
angle: 0.3,
alignment: Alignment.topLeft,
child: Container(
color: Colors.purpleAccent,
width: 200,
height: 200,
),
)
El ángulo de rotación aparece como valor de la propiedad
angle
.El origen por defecto es el centro del widget.
Antes de rotar…
Container( //grey background container (hidden here)
margin: EdgeInsets.only(top: 60, left: 60),
color: Colors.grey,
width: 200,
height: 200,
child: Container(
color: Colors.purpleAccent,
width: 200,
height: 200,
),
)
Rotar con el origen en la esquina superior izquierda
Usando el widget Transform
+ la propiedad transform
:
alignment: Alignment.topLeft
=origin: Offset(0,0)
- el origen por defecto es la esquina superior izquierda por lo que en este caso no es necesario dar valor a las propiedades
alignment
yorigin
Container( //grey background
margin: EdgeInsets.only(top: 60, left: 60),
color: Colors.grey,
width: 200,
height: 200,
child: Transform(
transform: Matrix4.rotationZ(0.3),
child: Container(
color: Colors.purpleAccent,
width: 200,
height: 200,
),
),
)
Usando el constructor Transform.rotate
:
alignment: Alignment.topLeft
=origin: Offset(-w/2, -h/2)
que en este caso esorigin: Offset(-100, -100)
- el origen por defecto es el centro por lo que si queremos que el widget rote alrededor de la esquina superior izquierda, será necesario dar valor bien a la propiedad
alignment
o bien a la propiedadorigin
Container(
margin: EdgeInsets.only(top: 60, left: 60),
color: Colors.grey,
width: 200,
height: 200,
child: Transform.rotate(
angle: 0.3,
alignment: Alignment.topLeft, //origin: Offset(-100, -100)
child: Container(
color: Colors.purpleAccent,
width: 200,
height: 200,
),
),
)
Rotar con el origen en la esquina superior derecha
Usando el widget Transform
+ la propiedad transform
:
- el origen por defecto es la esquina superior izquierda por lo que si queremos que el widget rote alrededor de la esquina superior derecha, usaremos la propiedad
alignment
o la propiedadorigin
alignment: Alignment.topRight
=origin: Offset(w,0)
que en el ejemplo seráorigin: Offset(200, 0)
Container(
margin: EdgeInsets.only(top: 60, left: 60),
color: Colors.grey,
width: 200,
height: 200,
child: Transform(
alignment: Alignment.topRight, //origin: Offset(200, 0)
transform: Matrix4.rotationZ(0.3),
child: Container(
color: Colors.purpleAccent,
width: 200,
height: 200,
),
),
)
Usando el constructor Transform.rotate
:
- el origen por defecto es el centro por lo que si queremos que el widget rote alrededor de la esquina superior derecha, tendremos que indicarlo
alignment: Alignment.topRight
=origin: Offset(w/2, -h/2)
siendo en este ejemploorigin: Offset(100, -100)
Container(
margin: EdgeInsets.only(top: 60, left: 60),
color: Colors.grey,
width: 200,
height: 200,
child: Transform.rotate(
angle: 0.3,
alignment: Alignment.topRight, //origin: Offset(100, -100)
child: Container(
color: Colors.purpleAccent,
width: 200,
height: 200,
),
),
)
Rotar con el origen en el centro
Usando el widget Transform
+ la propiedad transform
:
- el origen por defecto es la esquina superior izquierda por lo que daremos valor a la propiedad
alignment
o la propiedadorigin
para que rote alrededor del centro alignment: Alignment.center
=origin: Offset(w/2, h/2)
que en este caso esorigin: Offset(100, 100)
Container(
margin: EdgeInsets.only(top: 60, left: 60),
color: Colors.grey,
width: 200,
height: 200,
child: Transform(
alignment: Alignment.center, //origin: Offset(100, 100)
transform: Matrix4.rotationZ(0.3),
child: Container(
color: Colors.purpleAccent,
width: 200,
height: 200,
),
),
)
Usando el constructor Transform.rotate
:
- el origen por defecto es el centro por lo que no será necesario cambiar el valor por defecto con las propiedades
alignment
uorigin
Container(
margin: EdgeInsets.only(top: 60, left: 60),
color: Colors.grey,
width: 200,
height: 200,
child: Transform.rotate(
angle: 0.3,
child: Container(
color: Colors.purpleAccent,
width: 200,
height: 200,
),
),
)
Rotación alrededor del eje X o del eje Y (perspectiva 3D)
Explicación visual
En la siguiente escena, rotaremos la figura azul alrededor del eje X para dar como resultado la figura amarilla:
Antes de rotar, la figura azul está contenida en el plano XY:
Una vez rotada, la figura azul se convertirá en la figura amarilla. Si proyectamos dicha figura sobre el plano XY, obtenemos la figura verde.
Si la comparamos con la figura azul (antes de rotar) también en el plano XY, esta figura verde es más pequeña (en este ejemplo de rotación).
La siguiente figura es la perspectiva en 3D de la figura rotada. Así es como realmente vería el observador la figura rotada: vería más largo el lado cercano y más corto el lado lejano.
¿Cómo conseguimos en Flutter esta vista en 3D de la figura rotada?
Comencemos con la figura original antes de ser rotada:
Container(
margin: const EdgeInsets.only(left: 40, top: 80),
width: 250,
height: 160,
color: Colors.lightBlue,
)
Si la giramos directamente con transform: Matrix4.rotationX
:
Container(
margin: const EdgeInsets.only(left: 40, top: 80),
width: 250,
height: 160,
color: Colors.lightBlueAccent,
child: Transform(
transform: Matrix4.rotationX(-0.7),
alignment: Alignment.topCenter,
child: Container(
width: 250,
height: 160,
color: Colors.lightGreen,
),
),
)
estaremos rotando la figura pero viendo su proyección en el eje XY, es decir, veremos la figura verde:
Entonces para conseguir ver la perspectiva en 3D de la figura rotada,
usaremos transform: Matrix4.identity()..setEntry(3,2,0.001)
antes de aplicar la rotación. Es decir, estamos poniendo a 0.001 el elemento en la posición (3,2) de la matriz identidad. Y esto en la práctica, es crear una perspectiva 3D porque se hacen más grandes las longitudes cercanas y más pequeñas las longitudes alejadas.
Vamos a rotar -0,7 radianes alrededor del lado superior de la figura (que es paralelo al eje X). Y para ello, indicamos alignment: Alignment.topCenter
Container(
margin: const EdgeInsets.only(left: 40, top: 80),
width: 250,
height: 160,
color: Colors.lightBlueAccent,
child: Transform(
transform: Matrix4.identity()
..setEntry(3, 2, 0.001)
..rotateX(-0.7),
alignment: Alignment.topCenter,
child: Container(
width: 250,
height: 160,
color: Colors.amber,
),
),
)
Ejemplos con diferentes valores para el ángulo de rotación
- 0.7 radianes (-40.10º):
.....
transform: Matrix4.identity()
..setEntry(3, 2, 0.001)
..rotateX(-0.7),
alignment: Alignment.topCenter,
.....
-1.1 radianes (-63.02º):
.....
transform: Matrix4.identity()
..setEntry(3, 2, 0.001)
..rotateX(-1.1),
alignment: Alignment.topCenter,
.....
-1.4 radianes (-80.21º):
.....
transform: Matrix4.identity()
..setEntry(3, 2, 0.001)
..rotateX(-1.4),
alignment: Alignment.topCenter,
.....
-1.7 radianes (-97.40º):
.....
transform: Matrix4.identity()
..setEntry(3, 2, 0.001)
..rotateX(-1.7),
alignment: Alignment.topCenter,
.....
Tirar de la puerta y empujar la puerta
En los ejemplos anteriores hemos visto cómo conseguir una perspectiva 3D rotando alrededor del eje X.
Ahora vamos a hacerlo alrededor del eje Y a través de un ejemplo muy cotidiano: tirar de la puerta y empujar la puerta.
Primero implementaremos el hueco de la puerta (contenedor “hueco”):
Container( //hueco
margin: const EdgeInsets.only(left: 60, top: 60),
width: 200,
height: 400,
color: Colors.black87,
)
Ahora añadiremos el contenedor “puerta” como widget hijo del contenedor “hueco”:
Container( //hueco
margin: const EdgeInsets.only(left: 60, top: 60),
width: 200,
height: 400,
color: Colors.black87,
child: Container( //puerta
width: 300,
height: 400,
color: Colors.orangeAccent,
alignment: Alignment.centerRight,
padding: EdgeInsets.only(right: 30),
child: Container( // pomo
decoration: BoxDecoration(
color: Colors.deepOrange,
shape: BoxShape.circle,
),
width: 30,
height: 30,
),
),
)
Para conseguir el efecto de tirar de la puerta, rotaremos un pequeño ángulo positivo alrededor del eje Y y daremos una perspectiva 3D a la rotación.
Para hacer que el eje Y de rotación sea el lado izquierdo de la puerta, hacemos:alignment: Alignment.centerLeft
Container( // doorway
margin: const EdgeInsets.only(left: 60, top: 60),
width: 200,
height: 400,
color: Colors.black87,
child: Transform(
transform: Matrix4.identity()
..setEntry(3, 2, 0.001)
..rotateY(0.7),
alignment: Alignment.centerLeft,
child: Container( // door
width: 300,
height: 400,
color: Colors.orangeAccent,
alignment: Alignment.centerRight,
padding: EdgeInsets.only(right: 30),
child: Container(
decoration: BoxDecoration(
color: Colors.deepOrange,
shape: BoxShape.circle,
),
width: 30,
height: 30,
),
),
),
)
Si usamos un pequeño ángulo negativo en vez de uno positivo, conseguiremos el efecto empujar la puerta:
Experimentando con el parámetro de perspectiva
Llamamos parámetro de perspectiva al valor de la posición (3,2) de la matriz de transformación.
En ejemplos anteriores hemos usado un valor = 0.001 para este parámetro: transform: Matrix4.identity()..setEntry(3,2,0.001)
Este valor es la razón de que veamos la perspectiva 3D de un widget rotado o girado.
En los siguientes ejemplos veremos qué ocurre si mantenemos fijo el ángulo de rotación pero usamos diferentes valores para el parámetro de perspectiva:
Antes de la rotación
Ángulo fijo de rotación= -0.9 radianes y un parámetro de perspectiva que tomará los valores: 0.001, 0.002, 0.003 y 0.004
Y casi sin darnos cuenta hemos llegado al final de este artículo.
Si este artículo te ha parecido interesante o te ha ayudado, puedes agradecérmelo con unos cuantos 👏 👏 👏 👏 👏 👏 👏 👏.¡Muchas gracias por leerme! ¡Hasta el próximo artículo!
Se me olvidaba…
¡¡ No te pierdas la parte II de este artículo con desafíos para ponerte a prueba !!
Próximamente…