Skip to content

1 Coloring Your iOS App Navigation Bar

This is the first of a series of 4 posts about customizing the Navigation and Tab Bars. One of the best ways to give your iOS app a custom look is by theming the Navigation Bar. While it’s possible to do this using a ContainerControl or a Rectangle with carefully applied constraints, there’s a better and more direct approach—using Declares.

Keep reading to learn how to style your Navigation Bar.

Declares in Xojo allow you to access functions and constants from compiled libraries and system frameworks such as those provided by iOS or third-party developers. They’re a powerful way to extend your app’s capabilities beyond what is available in the Xojo framework.

In this case, we’ll use Declares to tap into the native iOS APIs and customize the appearance of a MobileScreen‘s NavigationBar, specifically to set its background color.

Start by adding a new module to your existing or empty iOS project. I’ve named this DeclaresForiOS. Within this module, add a new method using the following values:

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

Add the following snippet of code in the Associated Code Editor:

// Getting the ViewController for the received Screen
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

// Getting the NavigationBarController associated with the ViewController
Var nc As Ptr = NavigationController(controller)

// …and the NavigationBar itself from the 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)

// Getting the StandardAppearance object from the NavigationBar
Var appear As Ptr = StandardAppearance(nv)

// Setting the BackgroundColor to the StandardAppearance…
SetBackgroundColor(appear, colPtr)

// …and assigning the Standard Appearance again to the NavigationBar
SetStandardAppearance(nv, appear)

// If our app is running on iOS >= 15.0, then we need to set
// the same appearance to the scrollEdgeAppearance attribute on the NavigationBar
if (System.Version.MajorVersion >= 15.0) then
  SetScrollEdgeAppearance(nv, appear)
end if

As shown in the previous code, we’re calling the ColorGroupToUIColor method to convert a ColorGroup instance into a pointer to a valid UIColor. To support this, let’s add that helper method to our DeclaresForiOS module using the following values:

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

And type (or paste) the following snippet of code:

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

Let’s Color That!

And that is all the code we need! Now select the Screen1 item in the Navigator for the iOS project and add the following property to it:

  • Name: MyNavigationBarColor
  • Type: ColorGroup
  • Scope: Protected

With the Screen1 still selected in the Navigator, add the Opening event to it and add the following line of code:

MyNavigationBarColor = New ColorGroup( color.Red, color.Yellow )

As the last step, add the AppearanceChanged event to the Screen1 item; and add the following line of code to it:

me.NavigationBarColor = MyNavigationBarColor

Make sure the “Has Navigation Bar” attribute is enabled in the Inspector for Screen1, then run the project. If your Simulator or device is set to Light Mode, the Navigation Bar will appear red; if it’s in Dark Mode, it will appear yellow. You can switch between Light and Dark modes to see the Navigation Bar color transition between the two colors defined in your ColorGroup.

Download the example project from this link.

Happy coding!

Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón, Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at @XojoES or on the Xojo Forum.