👩🏫 登場人物
- 先生:ちょっとマニアックなプログラマー先生
- さくら:高校生でSwiftを勉強中
- ケン:クラスの技術マニア。フレームワークの裏側まで気になるタイプ
🎬 Scene 1:iOS 26アップデート後、タイトルが消えた!?
さくら「先生〜!iOS 26にしたら、ナビゲーションバーのタイトルが消えちゃいました!😭」
先生「おっ、それは“タイトル消失バグ”だね。最近よくあるやつだよ。」
ケン「タイトルって、普通 navigationItem.titleView にビューを入れてるやつですよね?」
先生「そう。でも iOS 26 から内部構造が変わって、Auto Layoutで配置するとズレたり消えたりするようになったんだ。」
🧠 Scene 2:Auto Layoutが悪さをしていた?
さくら「えっ、Auto Layoutって便利じゃないんですか?」
先生「もちろん便利。でも、ナビゲーションバーの中だけは特殊なんだ。
Apple が内部で自動的に制約を貼り直したりするから、開発者が指定した制約とぶつかってレイアウトが壊れることがある。」
ケン「なるほど…じゃあ、Auto Layoutをやめれば直るんですか?」
先生「そう。昔ながらのやり方に戻すんだ。つまり autoresizing mask + 手動 frame 調整!」
🛠 Scene 3:UIKitでの修正方法
💡基本方針
- Auto Layout(制約)を使わない
- autoresizing maskでサイズ変化に追従
-
viewDidLayoutSubviews()で frame を手動調整
✅ コード例(UIKit)
import UIKit
final class DemoViewController: UIViewController {
private let titleContainer = UIView()
private let titleLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
// タイトル用ラベル
titleLabel.text = "カスタムタイトル"
titleLabel.font = .boldSystemFont(ofSize: 17)
titleLabel.textAlignment = .center
// Auto Layoutを使わず、autoresizingで対応
titleContainer.translatesAutoresizingMaskIntoConstraints = true
titleContainer.autoresizingMask = [.flexibleWidth, .flexibleHeight]
titleLabel.translatesAutoresizingMaskIntoConstraints = true
titleLabel.autoresizingMask = [.flexibleWidth, .flexibleHeight]
// 階層に追加
titleContainer.addSubview(titleLabel)
navigationItem.titleView = titleContainer
// Large Titleを無効化(レイアウト揺れ防止)
navigationItem.largeTitleDisplayMode = .never
navigationController?.navigationBar.prefersLargeTitles = false
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// ナビゲーションバーのサイズに合わせて更新
if let bar = navigationController?.navigationBar {
titleContainer.frame = bar.bounds
titleLabel.frame = titleContainer.bounds
}
}
}
🔍 ここがポイント!
| 項目 | 内容 |
|---|---|
| Auto Layout無効化 | translatesAutoresizingMaskIntoConstraints = true |
| サイズ調整 | autoresizingMask = [.flexibleWidth, .flexibleHeight] |
| 手動更新 |
viewDidLayoutSubviews()でframeを再設定 |
| Large Title対策 |
largeTitleDisplayMode = .never 推奨 |
🪄 Scene 4:SwiftUIでも再現可能!
さくら「私はSwiftUI派なんですけど、これできるんですか?」
先生「もちろん!SwiftUIのツールバーは内部的にナビゲーションバーを使ってる。
だから UIKit のラベルを SwiftUI でラップすれば同じことができるよ。」
✅ コード例(SwiftUI)
import SwiftUI
// UIKitのUILabelをSwiftUIで使えるようにする
struct TitleHost: UIViewRepresentable {
func makeUIView(context: Context) -> UILabel {
let label = UILabel()
label.text = "カスタムタイトル"
label.font = .boldSystemFont(ofSize: 17)
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = true
label.autoresizingMask = [.flexibleWidth, .flexibleHeight]
return label
}
func updateUIView(_ uiView: UILabel, context: Context) {}
}
struct ContentView: View {
var body: some View {
Text("本文")
.toolbar {
ToolbarItem(placement: .principal) {
TitleHost()
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
.navigationBarTitleDisplayMode(.inline)
}
}
🧩 Scene 5:なぜこれで直るの?
ケン「Auto Layoutをやめるだけで、なんで直るんですか?」
先生「iOS 26ではナビゲーションバーの内部構造が変更されて、Auto Layoutの制約が
Appleの内部制約と衝突するようになったんだ。
その結果、タイトルのビューが0×0サイズになって“消えて見える”状態になってたんだよ。」
さくら「そんな落とし穴が…!じゃあ、autoresizingを使うと?」
先生「autoresizingは単純で、親ビューのサイズに合わせて伸び縮みするだけ。
つまりAppleの内部制約に左右されにくい。
Auto Layoutより“おおらか”な仕組みだから、バーの変更にも自然に追従できるんだ。」
📘 Scene 6:今日のまとめノート
| 💡ポイント | 内容 |
|---|---|
| 問題 | iOS 26でnavigationItem.titleViewが非表示になる |
| 原因 | Auto Layoutの制約がナビバーの内部変更と競合 |
| 対策 | Auto Layoutを使わず、autoresizing mask+手動frame調整で安定化 |
| SwiftUI対応 |
UIViewRepresentableでUILabelをラップして同様の処理を行う |
| 注意点 |
viewDidLayoutSubviews()で毎回frameを更新してサイズ変化に対応 |
👋 Scene 7:エンディング
先生「こうしてフレームワークの“裏側”を知ると、
単に“動く”だけじゃなく、“なぜ動くか”も理解できるようになるんだ。」
さくら「今日の授業で、“Auto Layoutを信じすぎない勇気”を学びました!」
ケン「次はタイトルバーにロゴとか検索バーも置いてみたいです!」
先生「いいね、それが次の課題だね!」
🧭 構造イメージ
UINavigationBar
├── UINavigationItem
│ └── titleView (UIView)
│ └── UILabel(タイトル表示)
└── viewDidLayoutSubviews()でframe更新
🔗 参考リンク
- Apple Developer Docs:UINavigationItem
- .NET MAUI PR #31832:Fix Navigation.SetTitleView not displaying on iOS 26
🏁 この記事のテーマ
「Auto Layoutは万能じゃない。
時には“昔ながらのゴムひも(autoresizing)”が一番強い。」