[Swift] UINavigationBarController の NavigationBar 高さ変更
はじめに
UINavigationController を使う時、UINavigationBar の高さを変更してみたいと思うことがありました。
UINavigationController と UINavigationBar をカスタマイズしてみて実用的なのかを解説していきたいと思います。
実践
CustomNavigationController.swift を作成
簡易イニシャライザを作成しておくことで、CustomNavigationController を便利に使うことができます。
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 の高さを差し引いた位置にずらす必要があります。
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 の拡張はできているがデバッグ画面では確認できなかった。
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 の高さを変更することは出来ました。
けれど、問題点も多くあまり実用的ではないような気がします。
以下に問題点を過剰書きしときます。これらを改善したりしてでも使いたいと思うならば実装してみてもいいかもしれません。
- 画面遷移の時、NavigationBar の高さが一時的に元に戻る
- NavigationBarItem の titleView に UIButton などを追加した時、タップできる範囲に限りがある
- これは公式でも対応していないらしく、改善することはハック的要素が強い
- 将来的に使えなくなる可能性がある
ここまで見ていただきありがとうございます、皆様の学びの助けになれば幸いです。
参考文献
Author And Source
この問題について([Swift] UINavigationBarController の NavigationBar 高さ変更), 我々は、より多くの情報をここで見つけました https://qiita.com/work16087y0rha/items/b907944945ecd85d4064著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .