Integración de texto y gráficos

Download SampleDescargar el ejemplo

Vea cómo determinar el tamaño de la cadena de texto representada para integrar texto con gráficos SkiaSharp

En este artículo se muestra cómo medir texto, escalar el texto a un tamaño determinado e integrar texto con otros gráficos:

Text surrounded by rectangles

Esa imagen también incluye un rectángulo redondeado. La clase SkiaSharp Canvas incluye los métodos DrawRect para dibujar un rectángulo y los métodos DrawRoundRect para dibujar un rectángulo con esquinas redondeadas. Estos métodos permiten definir el rectángulo como un valor de SKRect o de otras maneras.

La página Texto enmarcadocentra una corta cadena de texto en la página y la rodea con un marco compuesto por un par de rectángulos redondeados. En la clase FramedTextPage se muestra cómo se hace.

En SkiaSharp, se usa la clase SKPaint para establecer atributos de texto y fuente, pero también se puede usar para obtener el tamaño representado del texto. El principio del siguiente controlador de eventos PaintSurface llama a dos diferentes métodos MeasureText. La primera llamada MeasureText tiene un argumento string simple y devuelve el ancho de píxel del texto en función de los atributos de fuente actuales. A continuación, el programa calcula una nueva propiedad TextSize del objeto SKPaint en función de ese ancho representado, la propiedad TextSize actual y el ancho del área de visualización. Este cálculo está pensado para establecer TextSize para que la cadena de texto se represente al 90 % del ancho de la pantalla:

void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
    SKImageInfo info = args.Info;
    SKSurface surface = args.Surface;
    SKCanvas canvas = surface.Canvas;

    canvas.Clear();

    string str = "Hello SkiaSharp!";

    // Create an SKPaint object to display the text
    SKPaint textPaint = new SKPaint
    {
        Color = SKColors.Chocolate
    };

    // Adjust TextSize property so text is 90% of screen width
    float textWidth = textPaint.MeasureText(str);
    textPaint.TextSize = 0.9f * info.Width * textPaint.TextSize / textWidth;

    // Find the text bounds
    SKRect textBounds = new SKRect();
    textPaint.MeasureText(str, ref textBounds);
    ...
}

La segunda llamada MeasureText tiene un argumento SKRect, por lo que obtiene tanto un ancho como un alto del texto representado. La propiedad Height de este valor de SKRect depende de la presencia de letras mayúsculas, ascendentes y descendientes en la cadena de texto. Se notifican valores de Height diferentes para las cadenas de texto "mom", "cat" y "dog", por ejemplo.

Las propiedades Left y Top de la estructura SKRect indican las coordenadas de la esquina superior izquierda del texto representado si se muestra el texto mediante una llamada DrawText con posiciones X e Y de 0. Por ejemplo, cuando este programa se ejecuta en un simulador de iPhone 7, TextSize se asigna el valor 90.6254 como resultado del cálculo después de la primera llamada a MeasureText. El valor SKRect obtenido de la segunda llamada a MeasureText tiene los siguientes valores de propiedad:

  • Left = 6
  • Top = –68
  • Width = 664.8214
  • Height = 88;

Tenga en cuenta que las coordenadas X e Y que pasan al método DrawText especifican el lado izquierdo del texto en la línea base. El valor Top indica que el texto extiende 68 píxeles por encima de esa línea de base y (restando 68 de 88) 20 píxeles por debajo de la línea base. El valor Left de 6 indica que el texto comienza seis píxeles a la derecha del valor X en la llamada a DrawText. Esto permite el espaciado entre caracteres normal. Si desea mostrar el texto correctamente en la esquina superior izquierda de la pantalla, pase los negativos de estos valores Left y Top como coordenadas X e Y de DrawText, en este ejemplo, –6 y 68.

La estructura SKRect define varias propiedades y métodos útiles, algunos de los cuales se usan en el resto del controlador de PaintSurface. Los valores MidX y MidY indican las coordenadas del centro del rectángulo. (En el ejemplo de iPhone 7, esos valores son 338.4107 y –24). El código siguiente usa estos valores para el cálculo más sencillo de las coordenadas para centrar el texto en la pantalla:

void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
    ...
    // Calculate offsets to center the text on the screen
    float xText = info.Width / 2 - textBounds.MidX;
    float yText = info.Height / 2 - textBounds.MidY;

    // And draw the text
    canvas.DrawText(str, xText, yText, textPaint);
    ...
}

La estructura de información SKImageInfo también define una propiedad Rect de tipo SKRect, por lo que también puede calcular xText y yText de esta manera:

float xText = info.Rect.MidX - textBounds.MidX;
float yText = info.Rect.MidY - textBounds.MidY;

El controlador de PaintSurface concluye con dos llamadas a DrawRoundRect, que requieren argumentos de SKRect. Este valor SKRect se basa en el valor de SKRect obtenido del método MeasureText, pero no puede ser el mismo. En primer lugar, debe ser un poco más grande para que el rectángulo redondeado no dibuje sobre los bordes del texto. En segundo lugar, debe desplazarse en el espacio para que los valores Left y Top correspondan a la esquina superior izquierda donde se colocará el rectángulo. Estos dos trabajos se realizan mediante los métodos Offset y Inflate definidos por SKRect:

void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
    ...
    // Create a new SKRect object for the frame around the text
    SKRect frameRect = textBounds;
    frameRect.Offset(xText, yText);
    frameRect.Inflate(10, 10);

    // Create an SKPaint object to display the frame
    SKPaint framePaint = new SKPaint
    {
        Style = SKPaintStyle.Stroke,
        StrokeWidth = 5,
        Color = SKColors.Blue
    };

    // Draw one frame
    canvas.DrawRoundRect(frameRect, 20, 20, framePaint);

    // Inflate the frameRect and draw another
    frameRect.Inflate(10, 10);
    framePaint.Color = SKColors.DarkBlue;
    canvas.DrawRoundRect(frameRect, 30, 30, framePaint);
}

Después de eso, el resto del método es sencillo. Crea otro objeto SKPaint para los bordes y llama a DrawRoundRect dos veces. La segunda llamada usa un rectángulo inflado por otros 10 píxeles. La primera llamada especifica un radio de esquina de 20 píxeles. El segundo tiene un radio de esquina de 30 píxeles, por lo que parecen ser paralelos:

Triple screenshot of the Framed Text page

Puede girar el teléfono o el simulador lateralmente para ver el texto y el aumento del tamaño del marco.

Si solo necesita centrar algún texto en la pantalla, puede hacerlo aproximadamente sin medir el texto. En su lugar, establezca la propiedad TextAlign de SKPaint en el miembro de enumeración SKTextAlign.Center. La coordenada X que especifique en el método DrawText indica dónde se coloca el centro horizontal del texto. Si pasa el punto medio de la pantalla al método DrawText, el texto se centrará horizontalmente y casi centrado verticalmente porque la línea base se centrará verticalmente.

El texto se puede tratar como cualquier otro objeto gráfico. Una opción sencilla es mostrar el contorno de los caracteres de texto:

Triple screen shot of the Outlined Text page

Esto se logra simplemente cambiando la propiedad normal Style del objeto SKPaint de su valor predeterminado de SKPaintStyle.Fill a SKPaintStyle.Stroke y especificando un ancho de trazo. El controlador PaintSurface de la página Texto delineado muestra cómo se realiza:

void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
    SKImageInfo info = args.Info;
    SKSurface surface = args.Surface;
    SKCanvas canvas = surface.Canvas;

    canvas.Clear();

    string text = "OUTLINE";

    // Create an SKPaint object to display the text
    SKPaint textPaint = new SKPaint
    {
        Style = SKPaintStyle.Stroke,
        StrokeWidth = 1,
        FakeBoldText = true,
        Color = SKColors.Blue
    };

    // Adjust TextSize property so text is 95% of screen width
    float textWidth = textPaint.MeasureText(text);
    textPaint.TextSize = 0.95f * info.Width * textPaint.TextSize / textWidth;

    // Find the text bounds
    SKRect textBounds = new SKRect();
    textPaint.MeasureText(text, ref textBounds);

    // Calculate offsets to center the text on the screen
    float xText = info.Width / 2 - textBounds.MidX;
    float yText = info.Height / 2 - textBounds.MidY;

    // And draw the text
    canvas.DrawText(text, xText, yText, textPaint);
}

Otro objeto gráfico común es el mapa de bits. Este es un tema amplio que se trata en profundidad en la sección mapas de bits SkiaSharp, pero el siguiente artículo, conceptos básicos de mapa de bits en SkiaSharp, proporciona una breve introducción.