Como colorear la Barra de Navegación en tus Apps iOS

Una de las mejores formas de aplicar un tema en tus apps de iOS es coloreando la Barra de Navegación (NavigationBar) de la pantalla (Screen); y si bien es posible hacerlo ahora mismo mediante el uso de un ContainerControl o un Rectangle, en combinación con los Constraint adecuados… existe una mejor forma de lograrlo mediante el uso de los Declare. Continúa leyendo y te mostraré como.

Los Declares son la vía proporcionada por el lenguaje de programación Xojo para acceder a las funciones en las librerías o Frameworks ya compilados, ya sean los proporcionados por el sistema operativo propiamente dicho o bien los procedentes de terceros. En este caso utilizaremos varias de las funciones y sub-rutinas facilitadas por el propio Framework de iOS para definir el color utilizado por la NavigationBar de una instancia MobileScreen.

Comenzaremos añadiendo un nuevo Módulo llamado, por ejemplo, “DeclaresForiOS” a un proyecto de iOS nuevo… o bien a un proyecto de iOS ya existente.

A continuación, añade un nuevo método a dicho módulo utilizando los siguientes valores:

  • Method Name: NavigationBarColor
  • Parameters: Extends Screen As MobileScreen, Assigns Value As ColorGroup
  • Scope: Global

Y pega el siguiente fragmento de código en el Editor de Código asociado con el nuevo método:

// Obtenemos el ViewController correspondiente a la pantalla recibida
var controller as ptr = Screen.ViewControllerHandle

// https://developer.apple.com/documentation/uikit/uiviewcontroller/navigationcontroller?language=objc
Declare Function navigationController Lib "UIKit" Selector "navigationController" (controller as ptr) as ptr

// https://developer.apple.com/documentation/uikit/uinavigationcontroller/navigationbar?language=objc
Declare Function navigationBar Lib "UIKit" Selector "navigationBar" (controller as ptr) as ptr

// Obtenemos el objeto NavigationBarController asociado con el ViewController
var nc as ptr = navigationController(controller)

// …y el objeto NavigationBar propiamente dicho del NavigationBarController
var nv as ptr = navigationBar(nc)

Var colPtr As ptr
If value<>Nil Then
  colptr = ColorGroupToUIColor(value)
End If

// https://developer.apple.com/documentation/uikit/uinavigationbar/standardappearance?language=objc
Declare Function standardAppearance Lib "UIKit" Selector "standardAppearance" (obj As ptr) As ptr
Declare Sub setStandardAppearance Lib "UIKit" Selector "setStandardAppearance:" (obj as ptr, value as ptr)

// https://developer.apple.com/documentation/uikit/uinavigationbar/scrolledgeappearance?language=objc
Declare Sub setScrollEdgeAppearance Lib "UIKit" Selector "setScrollEdgeAppearance:" (obj as ptr, value as ptr)

// https://developer.apple.com/documentation/uikit/uibarappearance/backgroundcolor?language=objc
Declare Sub setBackgroundColor Lib "UIKit" Selector "setBackgroundColor:" (obj as ptr, value as ptr)

// Obtenemos el objeto StandardAppearance del NavigationBar
var appear as ptr = standardAppearance(nv)

// Definimos la propiedad BackgrounColor en el objeto standardappearance…
setBackgroundColor(appear, colptr)

// …Y asignamos nuevamente el objeto standardappearance a la NavigationBar
setStandardAppearance(nv, appear)

// Si nuestra app está ejecutándose en una versión de iOS superior a la versión 15.0
// entonces hemos de asignar el mismo objeto de apariencia al atributo
// scrolledgeappearance de la NavigationBar
if (System.Version.MajorVersion >= 15.0) then
  setScrollEdgeAppearance(nv, appear)
end if

Como puedes ver en el anterior fragmento de código, hacemos una llamada al método ColorGroupToUIColor para obtener un puntero a una instancia de UIColor a partir del ColorGroup recibido; de modo que hemos de añadir un método auxiliar a nuestro Módulo “DeclaresForiOS” utilizando los siguientes valores:

  • Method Name: ColorGroupToUIColor
  • Parameters: value As ColorGroup
    Return Type: Ptr
  • Scope: Global

Y escribe (o pega) el siguiente fragmento de código:

Var colorptr As ptr
Var c As Color

Select Case value.Mode
  
Case ColorGroup.modes.dual
  Var valueColors() As Color = value.values
  If Color.IsDarkMode And valueColors.LastIndex > 0 Then
    c = valueColors(1)
  Else
    c = valueColors(0)
  End If
Case ColorGroup.modes.Single
  Var valueColors() As Color = value.values
  c = valueColors(0)
  
End Select

If colorptr = Nil Then
  
  // https://developer.apple.com/documentation/foundation/nsclassfromstring(_:)?language=objc
  Declare Function NSClassFromString Lib "Foundation" (name As CFStringRef) As Ptr
  
  // https://developer.apple.com/documentation/uikit/uicolor/1621930-colorwithred
  Declare Function rgba Lib "UIKit" selector "colorWithRed:green:blue:alpha:" (cls As ptr, r As Double, g As Double, b As Double, a As Double) As ptr
  
  colorptr = rgba(NSClassFromString("UIColor"), c.Red/255, c.Green/255, c.Blue/255, 1-(c.Alpha/255))
  
End If

return colorptr

¡Hora de Colorear!

Y ese es todo el código que necesitamos. Selecciona ahora el ítem Screen1 en el Navegador de tu proyecto, y añádele la siguiente propiedad:

  • Name: mNavigationBarColor
  • Type: ColorGroup
  • Scope: Protected

Con el ítem Scren1 aun seleccionado en el Navegador, añádele el evento Opening y escribe la siguiente línea de código:

mNavigationBarColor = new ColorGroup( color.red, color.Yellow)

Como último paso, añade el evento AppearanceChanged al ítem Screen1, y añádele la siguiente línea de código:

me.NavigationBarColor = mNavigationBarColor

Asegúrate de que esté seleccionada la propiedad “Has Navigation Bar” en el Panel Inspector asociado con Screen1… y ejecuta el proyecto. Verás que la barra de navegación asociada con Screen1 aparecerá de color Rojo, siempre y cuando el dispositivo o el Simulador esté funcionando en Modo Claro; o de color Amarillo si el dispositivo o Simulador está ajustado en Modo Oscuro. También verás la transición entre ambos colores del ColorGroup asignado a medida que cambies el dispositivo o el Simulador entre los modos Claro / Oscuro.

¡Feliz programación!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *