[SWIFT] Learn how to customize the Navigation Bar from the sample app

Introduction

You can find instructions on how to customize the Navigation Bar on Apple's Developer site. https://developer.apple.com/documentation/uikit/uinavigationcontroller/customizing_your_app_s_navigation_bar

You can also download the sample app there, and learn how to customize the Navigation Bar by looking at both the article and the sample app.

It is stated that there are two ways to customize the NavigationBar.

--Indirectly change NavigationBar by changing UINavigationItem of ViewController --Modify NavigationController directly using Appearance proxy

We won't dig deeper into the meaning of the overview here. Let's take a look at the site description and sample apps in order.

Change BarStyle

How to change the appearance of the Navigation Bar. The sample code is as you can see.

//Change the style of the NavigationBar barStyle.Make the background black by setting it to black
self.navigationController!.navigationBar.barStyle = .black

//Make Navigation Bar translucent with isTranslucent
self.navigationController!.navigationBar.isTranslucent = true

//Change the color of the navigation bar title
self.navigationController!.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.white]

//Change the color of Item in NavigationBar
self.navigationController!.navigationBar.tintColor = #colorLiteral(red: 1, green: 0.99997437, blue: 0.9999912977, alpha: 1)

I put a comment in the sample code. Changing the style of the NavigationBar The barStyle actually had a style called .blackTranslucent, but since it became deprecated in iOS 13.0, we are taking the method of setting stlye to .black and isTranslucent to true. I will.

When this sample code is executed, it will look like the following. Simulator Screen Shot - iPhone 12 - 2020-12-17 at 14.30.13.png

Customize RightView

RightView is the area on the right side of the NavigationBar where you can apply custom UIViews and use UIBarButtonItems.

In the sample, three types of UIBarButtonItem are placed on the right side of the NavigationBar. This is a sample code.

//Generate UISegmentedControl with top and bottom images
let segmentedControl = UISegmentedControl(items: [
    UIImage(systemName: "arrow.up")!,
    UIImage(systemName: "arrow.down")!
])
//Do not show segment selected (default is false)
segmentedControl.isMomentary = true

//Use segmentedControl as a custom UIView for BarButtonItem
let segmentBarItem = UIBarButtonItem(customView: segmentedControl)
//Set Item on the right side
navigationItem.rightBarButtonItem = segmentBarItem

Since only the last two lines were posted on the site, I added a part of the source code from the sample application. In this example, UISegmentedControl is set as a bar button item on the right side of NavigationBar.

It looks like this. You should see the UISegmentedControl with the top and bottom images on the right side of the NavigationBar. Simulator Screen Shot - iPhone 12 - 2020-12-17 at 14.46.11.png

Customize TitleView

You can customize the TitleView of the NavigationBar by setting the UIView to navigationItem.titleView. The sample code sets the UISegmentedControl as a central custom TitleView.

let segmentTextContent = [
    NSLocalizedString("Image", comment: ""),
    NSLocalizedString("Text", comment: ""),
    NSLocalizedString("Video", comment: "")
]
let segmentedControl = UISegmentedControl(items: segmentTextContent)
self.navigationItem.titleView = segmentedControl

Simulator Screen Shot - iPhone 12 - 2020-12-18 at 18.46.10.png

Navigation Prompt changes

Prompt is a line of text that appears at the top of the Navigation Bar. Use the prompt property of UINavigationItem.

navigationItem.prompt = NSLocalizedString("Navigation prompts appear at the top.", comment: "")

The prompt was properly limited to one line, and even if I set the line feed code, it was invalid. Characters after the line feed code are ignored and are not displayed. Also, I set a large number of characters, but the characters that do not fit in the terminal width are reduced to the font size that can be displayed. It's the same behavior as setting adjustsFontSizeToFitWidth to true. In some cases, the font size will be reduced to an unrecognizable font size, so be aware of the number of characters. (It is not recommended to set too long characters)

Simulator Screen Shot - iPhone 12 - 2020-12-18 at 19.15.17.png

Customize the appearance of the Navigation Bar

Customize the background of the NavigationBar by adding barTintColor and background images. The sample code shows how to set the image.

guard let bounds = navigationController?.navigationBar.bounds else { return }

//Generate a gradient image by specifying a color
var backImageForDefaultBarMetrics =
    UIImage.gradientImage(bounds: bounds,
                          colors: [UIColor.systemBlue.cgColor, UIColor.systemFill.cgColor])
var backImageForLandscapePhoneBarMetrics =
    UIImage.gradientImage(bounds: bounds,
                          colors: [UIColor.systemTeal.cgColor, UIColor.systemFill.cgColor])

let navigationBarAppearance = self.navigationController!.navigationBar
//Default (used when a better background image cannot be found)
navigationBarAppearance.setBackgroundImage(backImageForDefaultBarMetrics, for: .default)
//Used when facing sideways on iPhone
navigationBarAppearance.setBackgroundImage(backImageForLandscapePhoneBarMetrics, for: .compact)

Simulator Screen Shot - iPhone 11 Pro - 2021-01-10 at 00.59.39.png

Customize the back button title

It is explained that the user can quickly switch between different stack levels by tapping and holding the back button. There is no sample code, but the sample app customizes the back button title for each ViewControler level in the stack. It may be a little difficult to convey if it is a sentence, so I will extract the code implemented in the sample application.

func makeViewController(_ level: Int) -> UIViewController {
    let viewController = UIViewController()
    viewController.navigationItem.backButtonTitle = "\(level)"
    return viewController
}

for level in 1..<10 {
    self.navigationController?.pushViewController(
        makeViewController(level), animated: false
    )
}

self.navigationController?.pushViewController(makeViewController(10), animated: true)

You can see that the back button is customized according to the level of each stack. By creating 10 view controllers and pushing them, the view controllers with customized buttons to return to the stack will be stacked.

Customize the back button with an image

If you leave the default back button on the NavigationBar, you'll see a set of text and a back arrow. It is a method to display the image prepared by the user without displaying it by customizing it. I'm using UINavigationBarAppearance. Appearance proxies are finally here.

let backButtonBackgroundImage = UIImage(systemName: "list.bullet")

//Generate UINavigationBarAppearance to change the settings of all UINavigationBars in CustomBackButtonNavController
let barAppearance =
    UINavigationBar.appearance(whenContainedInInstancesOf: [CustomBackButtonNavController.self])

//Change the back button (backIndicatorTransitionMaskImage also needs to be set)
barAppearance.backIndicatorImage = backButtonBackgroundImage
//Images used as content masks during Push and Pop transitions
barAppearance.backIndicatorTransitionMaskImage = backButtonBackgroundImage

//Generate UIBarButtonAppearance to change the settings of all UIBarButtonItems in CustomBackButtonNavController
let barButtonAppearance =
    UIBarButtonItem.appearance(whenContainedInInstancesOf: [CustomBackButtonNavController.self])
//Adjust the position of the back button text
barButtonAppearance.setBackButtonTitlePositionAdjustment(UIOffset(horizontal: 0, vertical: -5), for: .default)

You also need the code to get rid of the back button title. You can see that we have set an empty string to change the default setting.

let backBarButtton = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
navigationItem.backBarButtonItem = backBarButtton

When this is implemented, the back button will look like this:

Simulator Screen Shot - iPhone 11 Pro - 2021-01-10 at 18.35.16.png

Enlarge the title text of the Navigation Bar

This can be implemented very simply. However, the Large title is limited to Scroll Top, and when scrolled, it automatically switches to the normal display.

self.navigationController?.navigationBar.prefersLargeTitles = true

When Scroll Top

Simulator Screen Shot - iPhone 11 Pro - 2021-01-10 at 18.48.37.png

When scrolling

Simulator Screen Shot - iPhone 11 Pro - 2021-01-10 at 19.23.27.png

Changed the appearance of the Navigation Bar

It was used a while ago, How to use UINavigationBarAppearance and UIBarButtonItemAppearance.

let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
//Change background color
appearance.backgroundColor = UIColor.systemRed
//Change the title color of the Navigation Bar
appearance.titleTextAttributes = [.foregroundColor: UIColor.lightText]
//Normal Navigation Bar display
navigationItem.standardAppearance = appearance
//Display at the time of Scroll Top of Large title
navigationItem.scrollEdgeAppearance = appearance
//Display when the display mode is landscape
navigationItem.compactAppearance = appearance

let buttonAppearance = UIBarButtonItemAppearance()
//Change the title color of UIBarButton
buttonAppearance.normal.titleTextAttributes = [.foregroundColor: UIColor.systemGreen]
navigationItem.standardAppearance?.buttonAppearance = buttonAppearance
navigationItem.compactAppearance?.buttonAppearance = buttonAppearance

let doneButtonAppearance = UIBarButtonItemAppearance()
//Change the color of the Done button title
doneButtonAppearance.normal.titleTextAttributes = [.foregroundColor: UIColor.systemYellow]
navigationItem.standardAppearance?.doneButtonAppearance = doneButtonAppearance
navigationItem.compactAppearance?.doneButtonAppearance = doneButtonAppearance

The point here is that there are three types of Appearance: standardAppearance, scrollEdgeAppearance, and compactAppearance. The general meaning is described in the comments of the source code. Since the display mode of NavigationBar is slightly different, the settings are applied to each.

standardAppearance Simulator Screen Shot - iPhone 11 Pro - 2021-01-10 at 19.10.56.png

scrollEdgeAppearance Since the display of NavigationBar is standard in the sample application, The source code is added to introduce the display of scrollEdgeAppearance.

//add to
appearance.largeTitleTextAttributes = [.foregroundColor: UIColor.lightText]
navigationController?.navigationBar.prefersLargeTitles = true

Simulator Screen Shot - iPhone 11 Pro - 2021-01-10 at 19.21.24.png

compactAppearance Simulator Screen Shot - iPhone 11 Pro - 2021-01-10 at 19.22.00.png

Add menu to BarButtonItem

Adding a menu gives you easy access to the functionality of your application in one place. Add a UIMenu to the right of the UIBarButtonItem.

@IBOutlet var optionsBarItem: UIBarButtonItem!

func menuHandler(action: UIAction) {
    Swift.debugPrint("Menu handler: \(action.title)")
}

override func viewDidLoad() {
    let barButtonMenu = UIMenu(title: "", children: [
        UIAction(title: NSLocalizedString("Copy", comment: ""), image: UIImage(systemName: "doc.on.doc"), handler: menuHandler),
        UIAction(title: NSLocalizedString("Rename", comment: ""), image: UIImage(systemName: "pencil"), handler: menuHandler),
        UIAction(title: NSLocalizedString("Duplicate", comment: ""), image: UIImage(systemName: "plus.square.on.square"), handler: menuHandler),
        UIAction(title: NSLocalizedString("Move", comment: ""), image: UIImage(systemName: "folder"), handler: menuHandler)
    ])
    optionsBarItem.menu = barButtonMenu
}

UIBarButtonItem has a menu property, so I set the UIMenu there. However, please be careful about the OS version as it seems to be a property added from iOS14. In the sample, even if you press the button, the log is only output, so I think that you should change it according to the requirements of the application.

Menu closed

Simulator Screen Shot - iPhone 11 Pro - 2021-01-10 at 19.39.31.png

Menu open

Simulator Screen Shot - iPhone 11 Pro - 2021-01-10 at 19.39.37.png

Finally

We have introduced how to customize the UINavigationBar. I learned some things that I hadn't done before, and some things that I didn't understand well were sorted out. I'm glad if you can use it as a reference.

Recommended Posts

Learn how to customize the Navigation Bar from the sample app
How to transition from the [Swift5] app to the iPhone settings screen
How to run a Kotlin Coroutine sample from the command line
Customize how to divide the contents of Recyclerview
How to add sound in the app (swift)
[Swift] How to link the app with Firebase
How to connect to lcalhost from your smartphone and use the app under development
[swift5] How to transition from the app to an external site by specifying the URL
How to run the SpringBoot app as a service
How to write Scala from the perspective of Java
[Java] How to extract the file name from the path
List how to learn from Docker to AKS on AWS
How to determine the look-ahead request (Prefetch) from the browser
Kotlin may take the world from App to Web
iOS app development: Timer app (9. Customize the color of the progress bar)
[iOS] [Objective-C] How to update a widget from an Objective-C app
How to create a form to select a date from the calendar
Android app to select and display images from the gallery
How to get the longest information from Twitter as of 12/12/2016
How to disable Set-Cookie from API on the front side
How to migrate from JUnit4 to JUnit5
[Docker] How to access the host from inside the container. http://host.docker.internal:
How to apply C code format from the command line
[Swift] How to display when the quiz app answers correctly [Beginner]
[With sample code] Basics of Spring JDBC to learn with Blog app
[Swift] The color of the Navigation Bar is different (lighter) from the specified color.
[Java] How to convert from String to Path type and get the path
How to use the link_to method
How to use the include? method
How to push from Tarminal to GitHub
How to use the form_with method
How to find the average angle
How to learn JAVA in 7 days
How to add the delete function
The road from JavaScript to Java
How to change from HTML to Haml
How to interact with a server that does not crash the app
How to return a value from Model to Controller using the [Swift5] protocol
[Java] How to retrieve the parameters passed from html on the server side
How to run a GIF file from the Linux command line (Ubuntu)
[Swing] How to display an arbitrary name on the menu bar on Mac
How to compare only the time with Rails (from what time to what time, something like)
How to get the setting value (property value) from the database in Spring Framework
[Rails] How to apply the CSS used in the main app with Administrate
How to change app name in rails
[Java] How to use the File class
Investigate the replacement from Docker to Podman.
How to delete the wrong migration file
[Rails] How to convert from erb to haml
[Java] How to use the hasNext function
Language summary to learn from now on
[Java] How to use the HashMap class
[Ruby] From the basics to the inject method
How to delete the migration file NO FILE
[Rails] How to use the map method
[IOS] How to get data from DynamoDB
[Java] How to use the toString () method
[Swift] How to use Tab Bar Controller
Studying how to use the constructor (java)
[Processing × Java] How to use the loop
How to determine the number of parallels