Formas de Xamarin.Forms: transformaciones de objetos Path

Download SampleDescargar el ejemplo

Un elemento Transform define cómo transformar un objeto Path de un espacio de coordenadas a otro espacio de coordenadas. Cuando se aplica una transformación a un objeto Path, cambia cómo se representa el objeto en la interfaz de usuario.

Las transformaciones se pueden categorizar en cuatro clasificaciones generales: rotación, escalado, asimetría y traducción. Xamarin.Forms define una clase para cada una de estas clasificaciones de transformación:

  • RotateTransform, que gira un Path por un Angle especificado.
  • ScaleTransform, que escala un objeto Path por las cantidades ScaleX y ScaleY especificadas.
  • SkewTransform, que inclina un objeto Path por las cantidades AngleX y AngleY especificadas.
  • TranslateTransform, que mueve un objeto Path por las cantidades X y Y especificadas.

Xamarin.Forms también proporciona las siguientes clases para crear transformaciones más complejas:

  • TransformGroup, que representa una transformación compuesta formada por varios objetos de transformación.
  • CompositeTransform, que aplica varias operaciones de transformación a un objeto Path.
  • MatrixTransform, que crea transformaciones personalizadas que no proporcionan otras clases de transformación.

Todas estas clases derivan de la clase Transform, que define una propiedad Value de tipo Matrix, que representa la transformación actual como un objeto Matrix. Esta propiedad está respaldada por un objeto BindableProperty, lo que significa que puede ser destino de los enlaces de datos, y con estilo. Para obtener más información sobre la estructura Matrix, consulta Matriz de transformación.

Para aplicar una transformación a Path, crea una clase de transformación y establécela como el valor de la propiedad Path.RenderTransform.

Transformación de rotación

Una transformación de rotación gira un objeto Path en el sentido de las agujas del reloj sobre un punto especificado en un sistema de coordenadas X-Y bidimensional.

La clase RotateTransform, que se deriva de la clase Transform, define las siguientes propiedades:

  • Angle, de tipo double, representa el ángulo, en grados, de rotación en el sentido de las agujas del reloj. El valor predeterminado de esta propiedad es 0.0.
  • CenterX, de tipo double, representa la coordenada x del punto central de rotación. El valor predeterminado de esta propiedad es 0.0.
  • CenterY, de tipo double, representa la coordenada y del punto central de rotación. El valor predeterminado de esta propiedad es 0.0.

Estas propiedades están respaldadas por objetos BindableProperty, lo que significa que pueden ser destinos de los enlaces de datos, y que se les puede aplicar un estilo.

Las propiedades CenterX y CenterY especifican el punto sobre el que se gira el objeto Path. Este punto central se expresa en el espacio de coordenadas del objeto que se transforma. De forma predeterminada, la rotación se aplica a (0,0), que es la esquina superior izquierda del objeto Path.

En el ejemplo siguiente se muestra cómo girar un objeto Path:

<Path Stroke="Black"
      Aspect="Uniform"
      HorizontalOptions="Center"
      HeightRequest="100"
      WidthRequest="100"
      Data="M13.908992,16.207977L32.000049,16.207977 32.000049,31.999985 13.908992,30.109983z">
    <Path.RenderTransform>
        <RotateTransform CenterX="0"
                         CenterY="0"
                         Angle="45" />
    </Path.RenderTransform>
</Path>

En este ejemplo, el objeto Path se gira 45 grados sobre su esquina superior izquierda.

Transformación de escala

Una transformación de escala aumenta un objeto Path en el sistema de coordenadas X-Y bidimensional.

La clase ScaleTransform, que se deriva de la clase Transform, define las siguientes propiedades:

  • ScaleX, de tipo double, que representa el factor de escala del eje X. El valor predeterminado de esta propiedad es 1.0.
  • ScaleY, de tipo double, que representa el factor de escala del eje y. El valor predeterminado de esta propiedad es 1.0.
  • CenterX, de tipo double, que representa la coordenada X del punto central de esta transformación. El valor predeterminado de esta propiedad es 0.0.
  • CenterY, de tipo double, que representa la coordenada Y del punto central de esta transformación. El valor predeterminado de esta propiedad es 0.0.

Estas propiedades están respaldadas por objetos BindableProperty, lo que significa que pueden ser destinos de los enlaces de datos, y que se les puede aplicar un estilo.

El valor de ScaleX y ScaleY tiene un gran impacto en el escalado resultante:

  • Los valores entre 0 y 1 reducen el ancho y el alto del objeto escalado.
  • Los valores mayores que 1 aumentan el ancho y el alto del objeto escalado.
  • Los valores de 1 indican que el objeto no se escala.
  • Los valores negativos invierten el objeto de escala horizontal y verticalmente.
  • Los valores entre 0 y -1 invierten el objeto de escala y reducen su anchura y altura.
  • Los valores inferiores a -1 invierten el objeto y aumentan su anchura y altura.
  • Los valores de -1 invierten el objeto escalado, pero no cambian su tamaño horizontal o vertical.

Las propiedades CenterX y CenterY especifican el punto sobre el que se escala el objeto Path. Este punto central se expresa en el espacio de coordenadas del objeto que se transforma. De forma predeterminada, la rotación se aplica a (0,0), que es la esquina superior izquierda del objeto Path. Esto tiene el efecto de mover el objeto Path y también de hacer que parezca más grande, ya que cuando aplicas una transformación, cambias el espacio de coordenadas en la que reside el objeto Path.

En el ejemplo siguiente se muestra cómo se modifica la escala de un objeto Path:

<Path Stroke="Black"
      Aspect="Uniform"
      HorizontalOptions="Center"
      HeightRequest="100"
      WidthRequest="100"
      Data="M13.908992,16.207977L32.000049,16.207977 32.000049,31.999985 13.908992,30.109983z">
    <Path.RenderTransform>
        <ScaleTransform CenterX="0"
                        CenterY="0"
                        ScaleX="1.5"
                        ScaleY="1.5" />
    </Path.RenderTransform>
</Path>

En este ejemplo, el objeto Path se escala a 1,5 veces el tamaño.

Transformación del sesgo

Una transformación de sesgo sesga un objeto Path en el sistema de coordenadas x-y 2D, y es útil para crear la ilusión de profundidad 3D en un objeto 2D.

La clase SkewTransform, que deriva de la clase Transform, define las siguientes propiedades:

  • AngleX, de tipo double, que representa el ángulo sesgado del eje x, que se mide en grados en sentido contrario a las agujas del reloj desde el eje y. El valor predeterminado de esta propiedad es 0.0.
  • AngleY, de tipo double, que representa el ángulo sesgado del eje y, que se mide en grados en sentido contrario a las agujas del reloj desde el eje x. El valor predeterminado de esta propiedad es 0.0.
  • CenterX, de tipo double, que representa la coordenada x del centro de transformación. El valor predeterminado de esta propiedad es 0.0.
  • CenterY, de tipo double, que representa la coordenada y del centro de transformación. El valor predeterminado de esta propiedad es 0.0.

Estas propiedades están respaldadas por objetos BindableProperty, lo que significa que pueden ser destinos de los enlaces de datos, y que se les puede aplicar un estilo.

Para predecir el efecto de una transformación de sesgo, considere que AngleX sesga los valores del eje X relativos al sistema de coordenadas original. Por lo tanto, para AngleX de 30, el eje y gira 30 grados a lo largo del origen y sesga los valores de x en 30 grados a partir de ese origen. De forma similar, un AngleY de 30 sesga los valores del objeto Path en 30 grados a partir del origen.

Nota:

Para sesgar un objeto Path en su lugar, debes establecer las propiedades CenterX y CenterY en el punto central del objeto.

En el ejemplo siguiente se muestra cómo sesgar un objeto Path:

<Path Stroke="Black"
      Aspect="Uniform"
      HorizontalOptions="Center"
      HeightRequest="100"
      WidthRequest="100"
      Data="M13.908992,16.207977L32.000049,16.207977 32.000049,31.999985 13.908992,30.109983z">
    <Path.RenderTransform>
        <SkewTransform CenterX="0"
                       CenterY="0"
                       AngleX="45"
                       AngleY="0" />
    </Path.RenderTransform>
</Path>

En el siguiente ejemplo se aplica un sesgo horizontal de 45 grados a un objeto Path desde un punto central de (0,0).

Transformación de traslación

Una transformación de traslación mueve un objeto del sistema de coordenadas x-y bidimensional.

La clase TranslateTransform, que deriva de la clase Transform, define las siguientes propiedades:

  • X, de tipo double, que representa la distancia que se va a mover a lo largo del eje x. El valor predeterminado de esta propiedad es 0.0.
  • Y, de tipo double, que representa la distancia que se va a mover a lo largo del eje y. El valor predeterminado de esta propiedad es 0.0.

Estas propiedades están respaldadas por objetos BindableProperty, lo que significa que pueden ser destinos de los enlaces de datos, y que se les puede aplicar un estilo.

Los valores negativos X mueven un objeto a la izquierda, mientras que los valores positivos mueven un objeto a la derecha. Los valores negativos Y mueven un objeto hacia arriba, mientras que los valores positivos mueven un objeto hacia abajo.

En el ejemplo siguiente se muestra cómo usar un objeto Path:

<Path Stroke="Black"
      Aspect="Uniform"
      HorizontalOptions="Center"
      HeightRequest="100"
      WidthRequest="100"
      Data="M13.908992,16.207977L32.000049,16.207977 32.000049,31.999985 13.908992,30.109983z">
    <Path.RenderTransform>
        <TranslateTransform X="50"
                            Y="50" />
    </Path.RenderTransform>
</Path>

En este ejemplo, el objeto Path se mueve 50 unidades independientes del dispositivo hacia la derecha y 50 unidades independientes del dispositivo hacia abajo.

Varias transformaciones

Xamarin.Forms tiene dos clases que admiten la aplicación de varias transformaciones a un objeto Path. Son TransformGroup y CompositeTransform. TransformGroup realiza transformaciones en cualquier orden deseado, mientras que CompositeTransform realiza transformaciones en un orden específico.

Grupos de transformación

Los grupos de transformación representan transformaciones compuestas por varios objetos Transform.

La clase TransformGroup, que deriva de la clase Transform, define una propiedad Children, de tipo TransformCollection, que representa una colección de objetos Transform. Estas propiedades están respaldadas por objetos BindableProperty, lo que significa que pueden ser destinos de los enlaces de datos, y con formato de estilo.

El orden de las transformaciones es importante en una transformación compuesta que usa la clase TransformGroup. Por ejemplo, si primero gira, después escala y, a continuación, traslada, obtendrá un resultado diferente que si primero traslada, luego gira y, a continuación, escala. Un orden con motivos es significativo, porque las transformaciones como la rotación y el escalado se realizan con respecto al origen del sistema de coordenadas. El escalado de un objeto centrado en el origen genera un resultado diferente al escalado de un objeto que se ha alejado del origen. De forma similar, la rotación de un objeto centrado en el origen genera un resultado diferente a la rotación de un objeto que se ha alejado del origen.

En el ejemplo siguiente se muestra cómo realizar una transformación compuesta mediante la clase TransformGroup:

<Path Stroke="Black"
      Aspect="Uniform"
      HorizontalOptions="Center"
      HeightRequest="100"
      WidthRequest="100"
      Data="M13.908992,16.207977L32.000049,16.207977 32.000049,31.999985 13.908992,30.109983z">
    <Path.RenderTransform>
        <TransformGroup>
            <ScaleTransform ScaleX="1.5"
                            ScaleY="1.5" />
            <RotateTransform Angle="45" />
        </TransformGroup>
    </Path.RenderTransform>
</Path>

En este ejemplo, el objeto Path escala 1,5 veces su tamaño y luego gira 45 grados.

Transformaciones compuestas

Una transformación compuesta aplica varias transformaciones a un objeto.

La clase CompositeTransform, que deriva de la clase Transform, define las siguientes propiedades:

  • CenterX, de tipo double, que representa la coordenada x del punto central de esta transformación. El valor predeterminado de esta propiedad es 0.0.
  • CenterY, de tipo double, que representa la coordenada Y del punto central de esta transformación. El valor predeterminado de esta propiedad es 0.0.
  • ScaleX, de tipo double, que representa el factor de escala del eje x. El valor predeterminado de esta propiedad es 1.0.
  • ScaleY, de tipo double, que representa el factor de escala del eje y. El valor predeterminado de esta propiedad es 1.0.
  • SkewX, de tipo double, que representa el ángulo sesgado del eje x, que se mide en grados en sentido contrario a las agujas del reloj desde el eje y. El valor predeterminado de esta propiedad es 0.0.
  • SkewY, de tipo double, que representa el ángulo sesgado del eje y, que se mide en grados en sentido contrario a las agujas del reloj desde el eje x. El valor predeterminado de esta propiedad es 0.0.
  • Rotation, de tipo double, representa el ángulo, en grados, de rotación en el sentido de las agujas del reloj. El valor predeterminado de esta propiedad es 0.0.
  • TranslateX, de tipo double, que representa la distancia que se va a mover a lo largo del eje X. El valor predeterminado de esta propiedad es 0.0.
  • TranslateY, de tipo double, que representa la distancia que se va a mover a lo largo del eje y. El valor predeterminado de esta propiedad es 0.0.

Estas propiedades están respaldadas por objetos BindableProperty, lo que significa que pueden ser destinos de los enlaces de datos, y que se les puede aplicar un estilo.

CompositeTransform aplica transformaciones en este orden:

  1. Escalar (ScaleX y ScaleY).
  2. Sesgar (SkewX y SkewY).
  3. Girar (Rotation).
  4. Trasladar (TranslateXTranslateY).

Si quieres aplicar varias transformaciones a un objeto en un orden diferente, debes crear TransformGroup e insertar las transformaciones en el orden previsto.

Importante

CompositeTransform usa los mismos puntos centrales y CenterXCenterY, para todas las transformaciones. Si quieres especificar diferentes puntos centrales por transformación, usa TransformGroup,

En el ejemplo siguiente se muestra cómo realizar una transformación compuesta mediante la clase CompositeTransform:

<Path Stroke="Black"
      Aspect="Uniform"
      HorizontalOptions="Center"
      HeightRequest="100"
      WidthRequest="100"
      Data="M13.908992,16.207977L32.000049,16.207977 32.000049,31.999985 13.908992,30.109983z">
    <Path.RenderTransform>
        <CompositeTransform ScaleX="1.5"
                            ScaleY="1.5"
                            Rotation="45"
                            TranslateX="50"
                            TranslateY="50" />
    </Path.RenderTransform>
</Path>

En este ejemplo, el objeto Path escala 1,5 veces su tamaño, después gira 45 grados y luego se traslada 50 unidades independientes del dispositivo.

Transformaciones de matriz

Una transformación se puede describir en términos de una matriz de transformación afín 3x3, que realiza transformaciones en el espacio 2D. Esta matriz 3x3 se representa mediante la estructura Matrix, que es una colección de tres filas y tres columnas de valores double.

La clase Matrix define las propiedades siguientes:

  • Determinant, de tipo double, que obtiene el determinante de la matriz.
  • HasInverse, de tipo bool, que indica si la matriz es invertible.
  • Identity, de tipo Matrix, que obtiene una matriz de identidad.
  • HasIdentity, de tipo bool, que indica si la matriz es una matriz de identidad.
  • M11, de tipo double, que representa el valor de la primera fila y la primera columna de la matriz.
  • M12, de tipo double, que representa el valor de la primera fila y la segunda columna de la matriz.
  • M21, de tipo double, que representa el valor de la segunda fila y la primera columna de la matriz.
  • M22, de tipo double, que representa el valor de la segunda fila y la segunda columna de la matriz.
  • OffsetX, de tipo double, que representa el valor de la tercera fila y la primera columna de la matriz.
  • OffsetY, de tipo double, que representa el valor de la tercera fila y la segunda columna de la matriz.

Las propiedades OffsetX y OffsetY se denominan así porque especifican la cantidad para traducir el espacio de coordenadas a lo largo del eje X y el eje Y, respectivamente.

Además, la estructura Matrix expone una serie de métodos que se pueden usar para manipular los valores de matriz, incluidos Append, Invert, Multiply, Prepend y muchos más.

En la tabla siguiente, se muestra la estructura de una matriz de Xamarin.Forms:

M11

M12

0,0

M21

M22

0,0

OffsetX

OffsetY

1.0

Nota:

Una matriz de transformación afín tiene su columna final igual a (0,0,1), por lo que solo deben especificarse los miembros de las dos primeras columnas.

Manipulando los valores de la matriz, puedes girar, escalar, inclinar y traducir objetos Path. Por ejemplo, si cambias el valor OffsetX a 100, puedes usarlo para mover un objeto Path 100 unidades independientes del dispositivo a lo largo del eje X. Si cambias el valor M22 a 3, puedes usarlo para triplicar el alto actual de un objeto Path. Si cambias ambos valores, mueves el objeto Path 100 unidades independientes del dispositivo a lo largo del eje X y ajusta su alto a un factor de 3. Además, las matrices de transformación afín se pueden multiplicar para formar cualquier número de transformaciones lineales, como rotación y asimetría, seguidas de la traducción.

Transformaciones personalizadas

La clase MatrixTransform, que deriva de la clase Transform, define una propiedad Matrix, de tipo Matrix, que representa la matriz que define la transformación. Estas propiedades están respaldadas por objetos BindableProperty, lo que significa que pueden ser destinos de los enlaces de datos, y con formato de estilo.

Cualquier transformación que puedas describir con un objeto TranslateTransform, ScaleTransform, RotateTransform o SkewTransform puede describirse igualmente mediante MatrixTransform. Sin embargo, las clases TranslateTransform, ScaleTransform, RotateTransform y SkewTransform son más fáciles de conceptualizar que establecer los componentes vectoriales en Matrix. Por lo tanto, la clase MatrixTransform se usa normalmente para crear transformaciones personalizadas que no proporcionan las clases RotateTransform, ScaleTransform, SkewTransform o TranslateTransform.

En el ejemplo siguiente se muestra cómo transformar un objeto Path mediante MatrixTransform:

<Path Stroke="Black"
      Aspect="Uniform"
      HorizontalOptions="Center"
      Data="M13.908992,16.207977L32.000049,16.207977 32.000049,31.999985 13.908992,30.109983z">
    <Path.RenderTransform>
        <MatrixTransform>
            <MatrixTransform.Matrix>
                <!-- M11 stretches, M12 skews -->
                <Matrix OffsetX="10"
                        OffsetY="100"
                        M11="1.5"
                        M12="1" />
            </MatrixTransform.Matrix>
        </MatrixTransform>
    </Path.RenderTransform>
</Path>

En este ejemplo, el objeto Path se extiende, inclina y desplaza en las dimensiones X e Y.

Como alternativa, esto se puede escribir en un formato simplificado que usa un convertidor de tipos integrado en Xamarin.Forms:

<Path Stroke="Black"
      Aspect="Uniform"
      HorizontalOptions="Center"
      Data="M13.908992,16.207977L32.000049,16.207977 32.000049,31.999985 13.908992,30.109983z">
    <Path.RenderTransform>
        <MatrixTransform Matrix="1.5,1,0,1,10,100" />
    </Path.RenderTransform>
</Path>

En este ejemplo, la propiedad Matrix se especifica como una cadena delimitada por comas que consta de seis miembros: M11, M12, M21, M22, OffsetX, OffsetY. Aunque los miembros están delimitados por comas en este ejemplo, también se pueden delimitar por uno o varios espacios.

Además, el ejemplo anterior se puede simplificar aún más especificando los mismos seis miembros que el valor de la propiedad RenderTransform:

<Path Stroke="Black"
      Aspect="Uniform"
      HorizontalOptions="Center"
      RenderTransform="1.5 1 0 1 10 100"
      Data="M13.908992,16.207977L32.000049,16.207977 32.000049,31.999985 13.908992,30.109983z" />