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.
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.
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.
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
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)
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)
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.
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:
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
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
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
compactAppearance
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.
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