[XAMARIN FORMS] Ajuste del FontSize en base a la longitud del texto

Vamos a ver un sencillo ejemplo con Xamarin Forms para ajustar la fuente de una etiqueta de texto al espacio disponible en un Proyecto Xamarin.Forms.

Esto puede ser muy útil, para los casos en los que mostramos textos basados en idioma donde el espacio disponible para mostrarlo es limitado.

El calculo se basa en el número de caracteres de la cadena, las dimensiones del control/vista y en 2 variables por plataforma.

1. Espacio entre lineas. Para las fuentes por defecto en cada plataforma, este valor se calcula como
a) IOS: EspacioEntreLineas = 1.2 * TamañoFuente
b) Android: EspacioEntreLineas = 1.2 * TamañoFuente
c) Windows Phone: EspacioEntreLineas = 1.3 * TamañoFuente

2. Ancho medio de los caracteres.
AnchoMedio = 0.5 * TamañoFuente

La formula para calcular el tamaño de la fuenta es:

(int) Math.Sqrt(Label.Width * Label.Height / (NumeroCaracteres * EspacioEntreLineas * AnchoMedioCaracter)

A continuación mostramos el método completo que realiza el calculo

  private int CalcularTamaFuente(int anchoVista, int altoVista,string texto)
  {
      int tamaFuente = 10;
      int numeroCaracteres = 0;
      double factorEspacioLineas = 0;
      double factorMedioCaracter = 0;

      if ((anchoVista>0) && (altoVista > 0) && (!string.IsNullOrEmpty(texto)))
      {
          factorEspacioLineas = Device.OnPlatform(1.2, 1.2, 1.3);
          factorMedioCaracter = 0.5;
          numeroCaracteres = texto.Length;

          tamaFuente = (int) Math.Sqrt(anchoVista * altoVista /
          (numeroCaracteres * factorEspacioLineas * factorMedioCaracter));

          if (tamaFuente> MAX_TAMA_FUENTE)
          {
              tamaFuente = MAX_TAMA_FUENTE;
          }
          else if (tamaFuente < MIN_TAMA_FUENTE)
          {
              tamaFuente = MIN_TAMA_FUENTE;
          }
      }

      return tamaFuente;
  }

Hemos preparado un ejemplo en Xamarin Forms usando el patrón MVVM, con un control tipo “Entry” para introducir el texto y un control “Label” para mostrarlo y sobre el que realizaremos los ajuste sobre el tamaño de la fuente.

El XAML de la View es:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="AjustarTamaFuente.Views.AjustarFuenteView">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="200"></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Entry x:Name="txtTexto" Text="{Binding Texto}" Grid.Column="0" Grid.Row="0"></Entry>
        <Grid Grid.Column="0" Grid.Row="1">
            <Grid.RowDefinitions>
                <RowDefinition Height="*"></RowDefinition>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="300"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Label x:Name="lblTexto" Text="{Binding Texto}" WidthRequest="{Binding AnchoVista}" HeightRequest="{Binding AltoVista}" FontSize="{Binding TamaFuente}" ></Label>
        </Grid>
    </Grid>   
</ContentPage>

Mientras que la ViewModel es

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace AjustarTamaFuente.ViewModels
{
    public class AjustarFuenteViewModel:BindableObject
    {
        public const int MAX_TAMA_FUENTE = 100;
        public const int MIN_TAMA_FUENTE = 8;
        public static readonly BindableProperty TextoProperty = BindableProperty.Create(
          "Texto",
          typeof(string),
          typeof(AjustarFuenteViewModel),
          "Prueba de tamaño de fuente");

        public static readonly BindableProperty TamaFuenteProperty = BindableProperty.Create(
          "TamaFuente",
          typeof(int),
          typeof(AjustarFuenteViewModel),
          10);

        public static readonly BindableProperty AnchoVistaProperty = BindableProperty.Create(
          "AnchoVista",
          typeof(int),
          typeof(AjustarFuenteViewModel),
          300);

        public static readonly BindableProperty AltoVistaProperty = BindableProperty.Create(
          "AltoVista",
          typeof(int),
          typeof(AjustarFuenteViewModel),
          200);

        public string Texto
        {
            get
            {
                return (string) GetValue(TextoProperty);
            }
            set
            {
                SetValue(TextoProperty, value);
                if (!string.IsNullOrEmpty(value))
                {
                    TamaFuente = CalcularTamaFuente(AnchoVista, AltoVista, value);
                }
            }
        }

        public int TamaFuente
        {
            get
            {
                return (int) GetValue(TamaFuenteProperty);
            }
            set
            {
                SetValue(TamaFuenteProperty, value);
            }
        }

        public int AltoVista
        {
            get
            {
                return (int) GetValue(AltoVistaProperty);
            }
            set
            {
                SetValue(AltoVistaProperty, value);
            }
        }

        public int AnchoVista
        {
            get
            {
                return (int) GetValue(AnchoVistaProperty);
            }
            set
            {
                SetValue(AnchoVistaProperty, value);
            }
        }

        private int CalcularTamaFuente(int anchoVista, int altoVista,string texto)
        {
            int tamaFuente = 10;
            int numeroCaracteres = 0;
            double factorEspacioLineas = 0;
            double factorMedioCaracter = 0;

            if ((anchoVista>0) && (altoVista > 0) && (!string.IsNullOrEmpty(texto)))
            {
                factorEspacioLineas = Device.OnPlatform(1.2, 1.2, 1.3);
                factorMedioCaracter = 0.5;
                numeroCaracteres = texto.Length;

                tamaFuente = (int) Math.Sqrt(anchoVista * altoVista /
                (numeroCaracteres * factorEspacioLineas * factorMedioCaracter));

                if (tamaFuente> MAX_TAMA_FUENTE)
                {
                    tamaFuente = MAX_TAMA_FUENTE;
                }
                else if (tamaFuente < MIN_TAMA_FUENTE)
                {
                    tamaFuente = MIN_TAMA_FUENTE;
                }
            }

            return tamaFuente;
        }
    }
}

En las siguientes imagenes, se pueden ver 2 capturas de pantalla de un emulador Android.

En el siguiente enlace, podéis descargar el código del proyecto usado para este artículo