Pues eso… te voy a relacionar varios trucos sobre cómo usar el código (y el código de marcado XAML) para dispositivos móviles (Android, iOS y UWP -Windows 10-) usando Xamarin.Forms (Mono mobile) y seguramente servirá para .NET MAUI, la que será el sustituto de Xamarin cuando .NET 6.0 esté en fase release (sobre noviembre de este año 2021).
Nota:
El código mostrado a la hora de escribir este post (2 de junio de 2021 a las 11:15) es para Xamarin.Forms y C#.
Cuando tenga ejemplos de .NET MAUI lo indicaré si es diferente al de Xamarin.
Los trucos
El código con los ejemplos, ejercicios y soluciones están publicados en GitHub.
- Saber la plataforma (Android, iOS o UWP) y el tipo de dispositivo (Phone, Tablet, TV, Watch, Desktop)
- Poner varios valores en el código XAML usando OnPlatform, OnIdiom, etc.
- Ejercicio 1
- Ejercicio 2
- Si al crear un proyecto no te aparecen los emuladores ni dispositivos
- Acceder a los recursos definidos en ResourceDictionary o Application.Resources desde código (C#) (en otro post del 14-jun-2021)
Saber la plataforma (Android, iOS o UWP) y el tipo de dispositivo (Phone, Tablet, TV, Watch, Desktop)
Algunas veces es conveniente saber si la aplicación está funcionando en un dispositivo Android, iOS o compatible con UWP (Windows 10 escritorio o móvil, Xbox, etc.), tanbién si es un móvil, escritorio, tablet, etc.
La primera (la plataforma) se averigua con Platform y OnPlatform y los valores aceptados son los indicados en la tabla 1 (de la ayuda de Xamarin.Forms) que corresponden al tipo DevicePlatform:
La segunda (el tipo de dispositivo) se averigua con Idiom y OnIdiom y los valores de DeviceIdiom que son los que te muestro en la tabla 2.
Cuando usamos Platform o Idiom lo haremos por código usando la clase DeviceInfo (definida en Xamarin.Essentials).
OnPlatform y OnIdiom lo usaremos en el código XAML.
Ahora veremos ejemplos de código c# y XAML de estos dos casos.
Android | Gets the Android platform. |
iOS | Gets the iOS platform. |
macOS | Mac OS |
Tizen | Gets the Tizen platform |
tvOS | Gets the tvOS platform |
Unknown | Gets the unknown platform. |
UWP | Gets the UWP platform. |
watchOS | Gets the watchOS platform |
Tabla 1. Valores de la estructura DevicePlatform.
Desktop | Gets the desktop idiom. |
Phone | Gets the phone idiom. |
Tablet | Gets the tablet idiom. |
TV | Gets the TV idiom. |
Unknown | Gets the unknown idiom. |
Watch | Gets the watch idiom. |
Tabla 2. Valores de la estructura DeviceIdiom.
Código de ejemplo
Por código podemos usar DeviceInfo (habrá que importar el espacio de nombres Xamarin.Essentials) y las estructuras DevicePatform o DeviceIdiom según lo que queramos averiguar.
Nota:
En estos ejemplos estoy usando una página sencilla de tipo ContentPage de Xamarin.
En la que estarán definidos los controles usados en el código.
Por ejemplo, si queremos saber si el código está ejecutándose en un dispositivo UWP (por ejemplo, en Windows 10) o en Andoid o en iOS podemos hacer lo siguiente comprobando la propiedad Platform del tipo DeviceInfo:
// Saber la plataforma
if (DeviceInfo.Platform == DevicePlatform.UWP)
LabelDevicePlatform.Text = "Estás usando la plataforma UWP";
else if (DeviceInfo.Platform == DevicePlatform.Android)
LabelDevicePlatform.Text = "Estás usando la plataforma Android";
else if (DeviceInfo.Platform == DevicePlatform.iOS)
LabelDevicePlatform.Text = "Estás usando la plataforma iOS";
Lo mismo te interesa saber si se está ejecutando en un teléfono móvil una tableta o en el escritorio, para eso usaremos la propiedad Idiom de la clase DeviceInfo:
// Saber el tipo de dispositivo
if (DeviceInfo.Idiom == DeviceIdiom.Desktop)
LabelDeviceIdiom.Text = "Estás usando el escitorio.";
else if (DeviceInfo.Idiom == DeviceIdiom.Phone)
LabelDeviceIdiom.Text = "Estás usando un teléfono móvil.";
else if (DeviceInfo.Idiom == DeviceIdiom.Tablet)
LabelDeviceIdiom.Text = "Estás usando una tableta.";
Pero puede ser que lo que queremos es asignar un color según el código esté funcionando en una de las plataformas. En lugar de hacerlo por código, lo podemos hacer definiendo esa característica en el diseñador XAML.
Vamos a verlo aplicando un color al fondo de la etiqueta LabelDevicePlatform definida en el ejemplo.
<Label x:Name="LabelDevicePlatform" Padding="6"
TextColor="White"
BackgroundColor="{OnPlatform Android=#FA3F7E, iOS=#34C759, UWP=#0077DF}" />
En el código XAML es donde usaremos OnPlatform.
De igual forma podemos usar OnIdiom para saber el tipo de dispositivo.
<Label x:Name="LabelDeviceIdiom" Padding="6"
TextColor="{OnPlatform Android=Black, iOS=Blue, UWP=Green}"
BackgroundColor="Wheat"
FontSize="{OnIdiom Tablet=Small, Phone=Micro, Desktop=Medium}"/>
En ese código XAML hacemos las dos comprobaciones, la plataforma y el dispositivo y según sea aplicaremos un color u otro.
Si quieres hacer solo esa comprobación, por ejemplo para que en dispositivos de Apple (iOS) tengan un color y que en el resto tenga otro, podemos hacerlo de esta forma:
<Label Text="DeviceIdiom: " TextColor="{OnPlatform iOS=Green, Default=Red}"/>
En ese caso usamos el valor (o propiedad) Default que se aplicará a las plataformas (o dispositivos si se usa con OnIdiom) para las que no haya un valor concreto.
Poner varios valores en el código XAML usando OnPlatform, OnIdiom, etc.
Otra de las cosas que me ha pasado mientras estoy con esto de crear aplicaciones para dispositivos móviles y concretamente con el iPhone (iOS), en el que el texto mostrado en uno de los tipos de botones que estoy usando (para simular un Switch) es que el texto se queda pegado a los bordes del botón, mientras que en Android y UWP se quedaba separado.
Para solucionarlo necesitaba hacer dos cosas:
1- La más simple es poder añadir espacios delante y detrás del texto. Esto sería fácil si esa asignación la hago por código (c#), pero yo quería hacerla en el código de diseño (XAML).
2- Cambiar el Padding izquierdo y derecho.
El problema es que para el primer caso, tenía que asignar espacios delante y detrás del texto, pero ni usando el valor 255 (ALT+255) lo conseguí, ya que al ejecutar el código esos espacios se ignoran .
En el segundo caso, es que al asignar valores separados por comas da error, ya que después de cada coma se espera una propiedad.
Por ejemplo, lo del espacio.
Fíjate en el siguiente código XAML el valor del texto (propiedad Text) lo asigno usando un valor diferente según la plataforma.
Si es iOS uso un espacio delante y detrás de la palabra ATRÁS, en el resto de plataformas (Default) use ese mismo texto pero sin espacios:
<Button x:Name="btnAtras"
Text="{OnPlatform iOS= ATRÁS , Default=ATRÁS}"
HorizontalOptions="FillAndExpand"
Style="{StaticResource BtnNavegar}"
Clicked="btnAtras_Clicked"/>
Y si ese texto llevase comas, pues… ni se podría poner.
Ese sería el caso para cuando queremos asignar un valor que tenga varios argumentos separados por comas, como es el caso de Padding si no queremos asignar un solo valor para los 4 costados. Ya que solo me interesaba para la parte iaquierda y derecha, que si lo asignase de forma normal sería algo así:
Padding="6,0"
El primer valor se asignará a la izquierda y derecha (Left y Right) y el segundo valor arriba y abajo (Top y Botton).
Que queremos asignar 4 valores diferentes, lo haremos así:
Margin="4,5,6,7"
Los valores serían: 4 para la izquierda, 5 para arriba, 6 para la derecha y 7 para abajo.
La solución: Poner el texto entre comillas simples (las dobles no se pueden usar, ni siquiera usando teclas de ESCAPE, algo así: \»).
Por cierto, esa solución también es válida para el código HTML, cuando quieres poner comillas dentro de unas comillas, por ejemplo un valor style en el texto asignado a algo mediante código. Pero esa es otra historia.
Dicho lo dicho, la cosa quedaría de esta forma, si lo que se busca es que el padding izquierdo y derecho sea 6 para la plataforma iOS y 0 para el resto y que el texto incluya comas o espacios delante y/o detrás, si esos espacios están entro otros caracteres no hay que hacer nada especial.
<Label x:Name="LabelStatus" Style="{StaticResource LabelStatusWiz}"
Padding="{OnPlatform iOS='6,0', Default=0}"
Text="{OnPlatform Android=' Dispositivo \'Android\' ',
iOS=' Dispositivo iPhone (\'iOS\') ',
UWP='Dispositivo UWP (\'Windows 10, XBox\')'}"/>
Como ves el valor del Padding para iOS es ‘6,0’ (entre comillas simples).
Fíjate también que en ese código (para el valor de la propiedad Text) he usado \’ para indicar que quiero usar una comilla simple, esto solo funcionará si el texto completo está encerrado entre comillas simples.
Aquí tienes unas capturas de UWP: Windows 10 en el equipo local o lo que es lo mismo, usando el escritorio (figura 1), para Android (figura 2) y para iOS en un iPhone 7 Plus (figuras 3 y 4).
Observa los colores de las etiquetas (fondo y texto), así como en la parte de abajo que hay texto entre comillas simples.
Y observa que el padding para el botón ese con el texto tan largo, pues como que no sirve de mucho, ya que el botón pilla todo el ancho de la pantalla, pero sería útil si ese botón se está mostrando en un sitio que no lo expanda.
Si quieres, como ejercicio de práctica, puedes hacer lo siguiente:
Ejercicio 1:
Añade un panel (StackLayout) con la orientación horizontal, de esa forma los controles que metas dentro de ese stack se mostrarán uno al lado del otro, pon un Switch seguido de un botón con el texto «Un Switch» y después otro Switch y otro botón con el texto «Otro Switch» (o lo que te de la gana pero que no sea demasiado largo).
En este caso el texto no pillará todo el ancho y verás que no se ve igual en iOS / iPhone que en Android o UWP/Windows.
Si no puedes probarlos en distintos dispositivos emuladores, te pondré la respuesta con algunas capturas de los tres sistemas que utilizo con Xamarin.Forms.
Nota:
Probando el ejercicio, compruebo que el poner más espacios al final, no tienen el efecto deseado, así que… si es iOS usa el valor 6,0 para la propiedad Padding.
Otra cosa interesante que puedes hacer (ejercicio 2) es que las etiquetas estén alineadas en el centro vertical, es decir, para que no se vean con el texto tan arriba, sino en el centro de la propia etiqueta.
Pulsa en las imágenes para verlas a tamaño real.
Si miras las capturas 3 y 4 verás que en la última ya se ve bien el texto, tanto de la etiqueta de arriba como en la que tiene el fondo verde (la que indica que estás usando la plataforma iOS), para solucionar esa error, he vuelto a usar lo comentado en este post.
En el caso de la etiqueta de Xamarin he ajustado el valor de Padding para el iOS que sea más pequeño que para el resto.
<Label Text="Welcome to Xamarin.Forms!" FontSize="Title"
BackgroundColor="#96d1ff" Padding="{OnPlatform iOS=10,Default=40}"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
Para la etiqueta donde se muestra la plataforma en la que se está usando la aplicación, he optado por cambiar el tamaño de la letra.
<Label x:Name="LabelDevicePlatform" Padding="6"
FontSize="{OnPlatform iOS=Micro, Default=Small}"
TextColor="White"
BackgroundColor="{OnPlatform Android=#FA3F7E, iOS=#34C759, UWP=#0077DF}" />
Si al crear un proyecto no te aparecen los emuladores ni dispositivos
Pues eso… he creado un nuevo proyecto para Xamarin.Forms para estos ejemplos y ejercicios y al intentar probarlo en otra plataforma distinta a UWP, vamos al intentar probarlo en Android o iPhone no me salían las opciones de los emuladores o los dispositivos.
¿La solución?
Cerrar la solución y volverla a abrir, así de simple.
En la página de las soluciones a los ejercicios tienes las capturas del proyecto que he creado y que está publicado en GitHub (aquí más abajo tienes el enlace).
Y esto es todo.
Solo falta publicar el proyecto en GitHub, pero como lo he usado en la aplicación que tengo para las reservas de MKN (la empresa donde trabajo), tendré que crear un proyecto/solución para poder ponerlo en GitHub y así poder descargarlo, etc.
Ya avisaré. Avisado estás de que ya está publicado en GitHub 😉
La solución a los dos ejercicios las pondré en otro post y también estarán en GitHub.
El código en GitHub
elGuille-Ejemplos
Nos vemos.
Guillermo