La NavigationPage
Xamarin.Forms cuenta con diferentes páginas que aportan diferentes experiencias de navegación.
Entre las opciones, una de las más utilizadas es la experiencia ofrecida por NavigationPage. Esta experiencia de navegación consiste en una navegación jerárquica e la que el usuario puede navegar por las páginas hacia delante y hacia atrás. Se implementa la navegacion como una pila de páginas (LIFO).
El layout de la NavigationPage
El layout de la NavigationPage es dependiente de cada plataforma:
- En iOS, se utiliza una barra de navegación en la parte superior de la página mostrando título, y si es necesario, el botón de navegar atrás.
- En Android, se muestra también una barra de navegación en la parte superior con título, icono y botón de navegar atrás.
- En Windows, se muestra el título en una CommandBar situada en la parte superior. El botón de navegación atrás aparecerá en la barra de título de la ventana en escritorio y el botón virtual atrás en la parte inferior en móvil.
¿Cómo podemos personalizar la barra de navegación?
En este artículo vamos a aprender como:
- Ocultar la barra de navegación.
- Personalizar colores de la barra, del título, etc.
- Añadir un logo personalizado en la barra de navegación.
- Personalizar la fuente del título.
- Personalizar el icono del botón atrás.
Ocultar la barra de navegación
En determinadas páginass puede interesarnos no mostrar la barra de navegación. Es bastante sencillo controlar este comportamiento gracias al método SetHasNavigationBar.
En C#:
NavigationPage.SetHasNavigationBar(this, false);
En XAML:
NavigationPage.HasNavigationBar="False"
Personalizando colores
Continuamos con otra necesidad bastante común en muchas aplicaciones, personalizar el color de fondo y del título de la aplicación.
Con la propiedad BarBackgroundColor podemos definir el color de fondo de la barra de navegación mientras que con la propiedad BarTextColor definimos el color del título.
<NavigationPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" BarBackgroundColor="{StaticResource BarBackgroundColor}" BarTextColor="{StaticResource AccentColor}" > </NavigationPage>
El resultado en Android:
En iOS:
Y UWP:
Puedes descargar el código del ejemplo desde GitHub:
Fuente personalizada en el título
El uso de fuentes personalizadas suele ayudar a potenciar la imagen de marca en muchas aplicaciones móviles. Existen multitud de casos donde el título de la barra de navegación cuenta con una fuente personalizada aplicada.
¿Cómo logramos esto?.
Vamos a necesitar código específico en cada plataforma. Entran en juego los Custom Renderers.
Android
En Android comenzamos añadiendo la fuente a utilizar en la carpeta de Assets.
Tras añadir la fuente, creamos un Custom Render.
[assembly: ExportRenderer(typeof(CustomNavigationPage), typeof(CustomNavigationPageRenderer))] namespace CustomFontsNavigationPage.Droid.Renderers { public class CustomNavigationPageRenderer : NavigationPageRenderer { private Android.Support.V7.Widget.Toolbar _toolbar; public override void OnViewAdded(Android.Views.View child) { base.OnViewAdded(child); if (child.GetType() == typeof(Android.Support.V7.Widget.Toolbar)) { _toolbar = (Android.Support.V7.Widget.Toolbar)child; _toolbar.ChildViewAdded += OnToolbarChildViewAdded; } } protected override void Dispose(bool disposing) { base.Dispose(disposing); if(disposing) { _toolbar.ChildViewAdded -= OnToolbarChildViewAdded; } } private void OnToolbarChildViewAdded(object sender, ChildViewAddedEventArgs e) { var view = e.Child.GetType(); if (e.Child.GetType() == typeof(Android.Widget.TextView)) { var textView = (Android.Widget.TextView)e.Child; var spaceFont = Typeface.CreateFromAsset(Forms.Context.ApplicationContext.Assets, "Trashtalk.ttf"); textView.Typeface = spaceFont; _toolbar.ChildViewAdded -= Toolbar_ChildViewAdded; } } } }
Accedemos a la Toolbar (tras ser añadida) y posteriormente accedemos a sus elementos hijos, para acceder al título (TextView) y modificar la fuente.
Este mismo proceso será muy similar en otras plataformas.
iOS
También vamos a necesitar un Custom Render:
[assembly: ExportRenderer(typeof(CustomNavigationPage), typeof(CustomNavigationPageRenderer))] namespace CustomFontsNavigationPage.iOS.Renderers { public class CustomNavigationPageRenderer : NavigationRenderer { protected override void OnElementChanged(VisualElementChangedEventArgs e) { base.OnElementChanged(e); if (e.NewElement != null) { var textAttributes = new UITextAttributes(); textAttributes.Font = UIFont.FromName("Trashtalk", 20); UINavigationBar.Appearance.SetTitleTextAttributes(textAttributes); } } } }
Bastante sencillo. Accedemos a la NavigationBar en iOS y aprovechamos el método SetTitleTextAttributes para personalizar la fuente.
UWP
Y llegamos a Windows.
[assembly: ExportRenderer(typeof(CustomNavigationPage), typeof(CustomNavigationPageRenderer))] namespace CustomFontsNavigationPage.UWP.Renderers { public class CustomNavigationPageRenderer : NavigationPageRenderer { private CommandBar _commandBar; public CustomNavigationPageRenderer() { ElementChanged += OnElementChanged; } private void OnElementChanged(object sender, VisualElementChangedEventArgs e) { ElementChanged -= OnElementChanged; ContainerElement.Loaded += OnContainerElementLoaded; } private void OnContainerElementLoaded(object sender, Windows.UI.Xaml.RoutedEventArgs e) { ContainerElement.Loaded -= OnContainerElementLoaded; _commandBar = typeof(PageControl).GetTypeInfo().GetDeclaredField("_commandBar").GetValue(ContainerElement) as CommandBar; var commandBarContent = ((Border)_commandBar.Content); var textBlock = commandBarContent.Child as TextBlock; if(textBlock != null) { textBlock.FontFamily = new FontFamily("/Assets/Trashtalk.ttf#Trashtalk"); } } } }
Muy similar a lo realizado anteriormente en otras plataformas. Accedemos a la CommandBar utilizada como barra de navegación. A continuación, buscamos el TextBlock utilizado como título y utilizando la propiedad FontFamily, modificamos la fuente.
NOTA: Se puede definir el Element o parte compartida del Custom Renderer donde definir propiedades como el nombre de la fuente a utilizar o propiedades de tipo bool para aplicar la fuente personalizada o no en base a necesidades de cada página y hacer todo más personalizable.
El resultado en Android:
En iOS:
Y en Windows:
Puedes descargar el código del ejemplo desde GitHub:
Añadir un logo
Hemos hablado previamente del uso de fuentes personalizadas para conseguir trasmitir mejor la imagen de marca. Otro uso habitual es el de incluir una imagen (logo) en la barra de navegación.
¿Cómo lo conseguimos?.
Android
En Android podemos modificar el contenido de la Toolbar utilizando un layout AXML. Tras añadir la imagen a utilizar como logo en los recursos del proyecto, definimos un nuevo Layout:
<?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorPrimary" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" android:popupTheme="@style/ThemeOverlay.AppCompat.Light" android:elevation="5dp"> <ImageView android:id="@+id/logoImageLayout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:adjustViewBounds="true" android:src="@drawable/xamarinlogo" /> </android.support.v7.widget.Toolbar>
Sólo faltaría utilizarlo desde nuestra actividad principal:
ToolbarResource = Resource.Layout.ToolbarLogo;
iOS
En el caso de iOS, conseguimos el resultado con un sencillo Custom Render:
[assembly: ExportRenderer(typeof(MainView), typeof(LogoPageRenderer))] namespace CustomLogoNavigationPage.iOS.Renderers { public class LogoPageRenderer : PageRenderer { public override void ViewWillAppear(bool animated) { base.ViewWillAppear(animated); var image = UIImage.FromBundle("xamarin-logo.png"); var imageView = new UIImageView(new CGRect(0, 0, 140, 70)); imageView.ContentMode = UIViewContentMode.ScaleAspectFit; imageView.Image = image.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal); if (NavigationController != null) { NavigationController.TopViewController.NavigationItem.TitleView = imageView; } } } }
Accedemos a la NavigationBar y añadimos un UIImage utilizando la propiedad TitleView.
Windows
En Windows, el Custom Render necesario es muy similar a lo visto previamente:
[assembly: ExportRenderer(typeof(CustomNavigationPage), typeof(LogoPageRenderer))] namespace CustomLogoNavigationPage.UWP.Renderers { public class LogoPageRenderer : NavigationPageRenderer { private CommandBar _commandBar; public LogoPageRenderer() { ElementChanged += OnElementChanged; } private void OnElementChanged(object sender, VisualElementChangedEventArgs e) { ElementChanged -= OnElementChanged; ContainerElement.Loaded += OnContainerElementLoaded; } private void OnContainerElementLoaded(object sender, Windows.UI.Xaml.RoutedEventArgs e) { ContainerElement.Loaded -= OnContainerElementLoaded; _commandBar = typeof(PageControl).GetTypeInfo().GetDeclaredField("_commandBar").GetValue(ContainerElement) as CommandBar; var commandBarContent = ((Border)_commandBar.Content); var image = new Windows.UI.Xaml.Controls.Image(); image.Source = new BitmapImage(new Uri("ms-appx:///Assets/xamarin-logo.png")); commandBarContent.Child = image; } } }
Creamosun control Image y lo añadimos en la CommandBar.
El resultado en Android:
En iOS:
Y en Windows:
Puedes descargar el código del ejemplo desde GitHub:
¿One more thing?
¿Podemos personalizar aún más la barra de navegación?. Por supuesto!. Podemos tener necesidades como:
- Personalizar el icono de navegación atrás.
- Personalizar el texto asociado al botón para navegar atrás.
- Insertar elementos como barras de búsqueda.
- Etc.
Este conjunto de cambios, los veremos en otro artículo.
Recuerda que cualquier comentario o pregunta es bienvenido en los comentarios del artículo!.