Flutter España
Published in

Flutter España

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 con Matrix4.rotationZ(double radians) como valor para la propiedad transform:
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

Rotación alrededor del eje Z con origen en 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 es origin: 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 propiedad origin
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 propiedad origin
  • 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 ejemplo origin: 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 propiedad origin para que rote alrededor del centro
  • alignment: Alignment.center = origin: Offset(w/2, h/2) que en este caso es origin: 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…

--

--

Actualidad de Flutter en España y Español

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store