[Swift] UINavigationBarController의 NavigationBar 높이 변경
소개
UINavigationController를 사용할 때 UINavigationBar의 높이를 변경하고 싶을 수있었습니다.
UINavigationController 와 UINavigationBar 를 커스터마이즈 해 보고 실용적인가를 해설해 가고 싶습니다.
실천
CustomNavigationController.swift 만들기
간단한 이니셜라이저를 만들어 CustomNavigationController를 편리하게 사용할 수 있습니다.
CustomNavigationController.swiftclass CustomNavigationController: UINavigationController {
// 1. イニシャライザ
override init(rootViewController: UIViewController) {
super.init(rootViewController: rootViewController)
}
// 2. イニシャライザ
override init(navigationBarClass: AnyClass?, toolbarClass: AnyClass?) {
super.init(navigationBarClass: navigationBarClass, toolbarClass: toolbarClass)
}
// イニシャライザ
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
// 必須イニシャライザ
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// 簡易イニシャライザ (1. 2. をまとめ便利にしたもの)
convenience init(rootViewController:UIViewController , navigationBarClass:AnyClass?, toolbarClass: AnyClass?){
self.init(navigationBarClass: navigationBarClass, toolbarClass: toolbarClass)
self.viewControllers = [rootViewController]
}
override func viewDidLoad() {
super.viewDidLoad()
// 他にすることがある場合
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
CustomNavigationBar.swift 만들기
NavigationBar의 높이를 변경하려면 사용자 지정 클래스를 만들어야 합니다.sizeThatFits(_ size: CGSize)
는, 지정된 사이즈에 최적인 사이즈를 계산해 돌려주도록(듯이) 뷰에 요구하는 메소드이므로, 이하와 같이 NavigationBar 의 높이를 지정하면 기대대로 움직여 줍니다.
이 때 주의점이 있고 iPhone X 이후의 경우는 SafeArea 계산이 필요합니다.
또한 NavigationBarContentView의 위치가 어긋나므로 NavigationBar의 높이에서 NavigationBarContentView의 높이를 뺀 위치로 옮겨야 합니다.
CustomNavigationBar.swiftclass CustomNavigationBar: UINavigationBar {
// NavigationBar の高さ
private let barHeight: CGFloat = 100
// イニシャライザ
override init(frame: CGRect) {
super.init(frame: frame)
self.commonInit()
}
// 必須イニシャライザ
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func commonInit() {
// NavigationBar の色
self.barTintColor = .white
}
// 1. 指定されたサイズに最適なサイズを計算して返すようにビューに要求
override func sizeThatFits(_ size: CGSize) -> CGSize {
var newSize = super.sizeThatFits(size)
var topInset: CGFloat = 0.0
// iPhone X 以降 (SafeArea の高さを取得)
if #available(iOS 11.0, *) {
topInset = superview?.safeAreaInsets.top ?? 0
}
// NavigationBar の高さを設定
newSize.height = barHeight + topInset
return newSize
}
override func layoutSubviews() {
super.layoutSubviews()
if #available(iOS 11.0, *) {
for subview in subviews {
let stringFromClass = NSStringFromClass(subview.classForCoder)
// NavigationBar の高さを調整
if stringFromClass.contains("UIBarBackground") {
let topInset: CGFloat = superview?.safeAreaInsets.top ?? 0
subview.frame = CGRect(origin: CGPoint(x: 0, y: -topInset), size: sizeThatFits(self.bounds.size))
}
// UINavigationBarContentView の位置を調整
if stringFromClass.contains("UINavigationBarContentView") {
let y = (barHeight - subview.frame.height)
subview.frame.origin.y = y
}
}
}
}
}
NavigationBar의 높이를 변경할 수 있습니다.
SafeArea도 문제없이 계산할 수 있는 것 같습니다.
그러나 언뜻 보면 예상대로 보이지만 디버그 화면을 확인하면 문제점이있었습니다.
RootViewController의 View가 NavigationBar와 겹쳐져 있습니다.
이 문제를 개선하려면 SafeArea를 확장해야 합니다.
결과
SafeArea를 확장한 후 디버그 화면을 확인해도 View 중첩은 개선되지 않았습니다.
따라서 View 를 추가할 때 상위 제약을 SafeArea 로 지정하면 예상대로 움직여 주었습니다.
아마 SafeArea의 확장은 되어 있었지만 디버그 화면에서는 확인할 수 없었다.
RootViewController.swiftclass RootViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// 背景色
self.view.backgroundColor = .systemGreen
// NavigationBar のタイトル
self.title = "Test"
// SafeArea の拡張
if #available(iOS 11.0, *) {
// NavigationBar の高さ - 元の NavigationBar の高さ
additionalSafeAreaInsets.top = 100 - 44
}
// 赤い正方形 を追加
self.view.addSubview(topView)
// 制約を設定
topView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor).isActive = true
topView.widthAnchor.constraint(equalToConstant: 100).isActive = true
topView.heightAnchor.constraint(equalToConstant: 100).isActive = true
topView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
}
}
사이고에게
꽤 복잡한 내용이 되었기 때문에, 이해하기 어려운 부분도 있을지도 모릅니다만, NavigationBar 의 높이를 변경할 수 있었습니다.
하지만 문제점도 많아 별로 실용적이지 않은 것 같습니다.
아래에 문제점을 과도하게 쓸 때: 이것들을 개선하거나 해도 사용하고 싶다면 구현해 봐도 좋을지도 모릅니다.
CustomNavigationController.swift 만들기
간단한 이니셜라이저를 만들어 CustomNavigationController를 편리하게 사용할 수 있습니다.
CustomNavigationController.swift
class CustomNavigationController: UINavigationController {
// 1. イニシャライザ
override init(rootViewController: UIViewController) {
super.init(rootViewController: rootViewController)
}
// 2. イニシャライザ
override init(navigationBarClass: AnyClass?, toolbarClass: AnyClass?) {
super.init(navigationBarClass: navigationBarClass, toolbarClass: toolbarClass)
}
// イニシャライザ
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
// 必須イニシャライザ
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// 簡易イニシャライザ (1. 2. をまとめ便利にしたもの)
convenience init(rootViewController:UIViewController , navigationBarClass:AnyClass?, toolbarClass: AnyClass?){
self.init(navigationBarClass: navigationBarClass, toolbarClass: toolbarClass)
self.viewControllers = [rootViewController]
}
override func viewDidLoad() {
super.viewDidLoad()
// 他にすることがある場合
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
CustomNavigationBar.swift 만들기
NavigationBar의 높이를 변경하려면 사용자 지정 클래스를 만들어야 합니다.
sizeThatFits(_ size: CGSize)
는, 지정된 사이즈에 최적인 사이즈를 계산해 돌려주도록(듯이) 뷰에 요구하는 메소드이므로, 이하와 같이 NavigationBar 의 높이를 지정하면 기대대로 움직여 줍니다.이 때 주의점이 있고 iPhone X 이후의 경우는 SafeArea 계산이 필요합니다.
또한 NavigationBarContentView의 위치가 어긋나므로 NavigationBar의 높이에서 NavigationBarContentView의 높이를 뺀 위치로 옮겨야 합니다.
CustomNavigationBar.swift
class CustomNavigationBar: UINavigationBar {
// NavigationBar の高さ
private let barHeight: CGFloat = 100
// イニシャライザ
override init(frame: CGRect) {
super.init(frame: frame)
self.commonInit()
}
// 必須イニシャライザ
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func commonInit() {
// NavigationBar の色
self.barTintColor = .white
}
// 1. 指定されたサイズに最適なサイズを計算して返すようにビューに要求
override func sizeThatFits(_ size: CGSize) -> CGSize {
var newSize = super.sizeThatFits(size)
var topInset: CGFloat = 0.0
// iPhone X 以降 (SafeArea の高さを取得)
if #available(iOS 11.0, *) {
topInset = superview?.safeAreaInsets.top ?? 0
}
// NavigationBar の高さを設定
newSize.height = barHeight + topInset
return newSize
}
override func layoutSubviews() {
super.layoutSubviews()
if #available(iOS 11.0, *) {
for subview in subviews {
let stringFromClass = NSStringFromClass(subview.classForCoder)
// NavigationBar の高さを調整
if stringFromClass.contains("UIBarBackground") {
let topInset: CGFloat = superview?.safeAreaInsets.top ?? 0
subview.frame = CGRect(origin: CGPoint(x: 0, y: -topInset), size: sizeThatFits(self.bounds.size))
}
// UINavigationBarContentView の位置を調整
if stringFromClass.contains("UINavigationBarContentView") {
let y = (barHeight - subview.frame.height)
subview.frame.origin.y = y
}
}
}
}
}
NavigationBar의 높이를 변경할 수 있습니다.
SafeArea도 문제없이 계산할 수 있는 것 같습니다.
그러나 언뜻 보면 예상대로 보이지만 디버그 화면을 확인하면 문제점이있었습니다.
RootViewController의 View가 NavigationBar와 겹쳐져 있습니다.
이 문제를 개선하려면 SafeArea를 확장해야 합니다.
결과
SafeArea를 확장한 후 디버그 화면을 확인해도 View 중첩은 개선되지 않았습니다.
따라서 View 를 추가할 때 상위 제약을 SafeArea 로 지정하면 예상대로 움직여 주었습니다.
아마 SafeArea의 확장은 되어 있었지만 디버그 화면에서는 확인할 수 없었다.
RootViewController.swiftclass RootViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// 背景色
self.view.backgroundColor = .systemGreen
// NavigationBar のタイトル
self.title = "Test"
// SafeArea の拡張
if #available(iOS 11.0, *) {
// NavigationBar の高さ - 元の NavigationBar の高さ
additionalSafeAreaInsets.top = 100 - 44
}
// 赤い正方形 を追加
self.view.addSubview(topView)
// 制約を設定
topView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor).isActive = true
topView.widthAnchor.constraint(equalToConstant: 100).isActive = true
topView.heightAnchor.constraint(equalToConstant: 100).isActive = true
topView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
}
}
사이고에게
꽤 복잡한 내용이 되었기 때문에, 이해하기 어려운 부분도 있을지도 모릅니다만, NavigationBar 의 높이를 변경할 수 있었습니다.
하지만 문제점도 많아 별로 실용적이지 않은 것 같습니다.
아래에 문제점을 과도하게 쓸 때: 이것들을 개선하거나 해도 사용하고 싶다면 구현해 봐도 좋을지도 모릅니다.
class RootViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// 背景色
self.view.backgroundColor = .systemGreen
// NavigationBar のタイトル
self.title = "Test"
// SafeArea の拡張
if #available(iOS 11.0, *) {
// NavigationBar の高さ - 元の NavigationBar の高さ
additionalSafeAreaInsets.top = 100 - 44
}
// 赤い正方形 を追加
self.view.addSubview(topView)
// 制約を設定
topView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor).isActive = true
topView.widthAnchor.constraint(equalToConstant: 100).isActive = true
topView.heightAnchor.constraint(equalToConstant: 100).isActive = true
topView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
}
}
꽤 복잡한 내용이 되었기 때문에, 이해하기 어려운 부분도 있을지도 모릅니다만, NavigationBar 의 높이를 변경할 수 있었습니다.
하지만 문제점도 많아 별로 실용적이지 않은 것 같습니다.
아래에 문제점을 과도하게 쓸 때: 이것들을 개선하거나 해도 사용하고 싶다면 구현해 봐도 좋을지도 모릅니다.
여기까지 봐 주셔서 감사합니다, 여러분의 배움의 도움이 되면 다행입니다.
참고문헌
Reference
이 문제에 관하여([Swift] UINavigationBarController의 NavigationBar 높이 변경), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/work16087y0rha/items/b907944945ecd85d4064텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)