【UIKit】iOS 26 の Liquid Glass に対して既存アプリで対応したこと
どうも。Reoです。久しぶりに Swift の記事です!
はじめに
2025年9月にリリースされた iOS26 では、「Liquid Glass」 という新デザインが採用されました。
私が関わっているiOSアプリでも、この Liquid Glass の影響を受けました。このアプリはかなり前から運用しているアプリとなり、アプリ全体は UIKit で構築されています。
自分の調べた範囲のメモになりますが、記事として残しておこうと思います。 UIKitでの影響について、より詳しい内容は What's New in UIKit がとても参考になります。
主な影響
主に影響を受けた部分は次の3つです。
- UITabbar
- UIToolbar
- UINavigationController
現時点では、Xcode 26 でビルドすることにより、それぞれ Liquid Glass のデザインに自動で変更されます。
iOS18 以前のデザインを使いたい
暫定的に UIDesignRequiresCompatibilityを使うことで、iOS 18以前のデザインを使うことがで きます。
Info.plist にUIDesignRequiresCompatibility YES を設定すると、アプリ全体の Liquid Glass が無効になります。
ただし、この方法は次の iOS 27 では消滅することが決まっているらしく、暫定的な対応でしかありません。
つまり、現時点では iOS18 以前のようなデザインを継続したい場合、次の iOS 27 のリリース前に自作したものに置き換える必要がありそうです。
UITabbar の対応
自分たちのアプリではUITabbarController は使わず、直接 UITabbar を配置していました。このとき UITabbar の高さを固定で設定していました。
iOS 26 ではこの高さが悪さをして UITabbar が潰れて表示してしまったので、正しいAutoLayoutを設定して修正しました。
また、スクロールするコンテンツが ViewController に設定されている場合には、タブバーの下に潜り込むように設定した方が良いでしょう。(まだしてない)
タブの表示が重い時に、Liquid Glass のアニメーションが半端な状態で少し固まる動作が目立つようになってしまったので、パフォーマンスも改善したいところです。(まだしてない)
UIToolbar の対応
UIToolbar は、次のように UITextField の AccessoryView として利用していました。
let toolbar = UIToolbar()
let closeButton = UIBarButtonItem(title: "完了", style: .done, target: self, action: #selector(onTapCloseButton(_:)))
let flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
toolbar.setItems([flexibleSpace, closeButton], animated: false)
textField.inputAccessoryView = toolbar
Liquid Glass 対応として行ったのはtoolbar.tintColor と toolbar 自体の高さ修正です。
if #available(iOS 26.0, *) {
// キーボードとボタンの間に余白を設けるため
toolbar.heightAnchor.constraint(equalToConstant: 52).isActive = true
closeButton.style = .plain
} else {
// iOS 18 以前では UIToolbar の背景があるデザイン
toolbar.tintColor = .white
toolbar.barTintColor = .black
}
iOS 26 で iOS 18 以前の設定のまま、 toolbar.tintColor = .white と toolbar.barTintColor = .black を設定した場合を比較してみます。
| iOS 18 以前 | iOS 26 |
|---|---|
|
|
このように、iOS26 では barTintColor の色は無効となり、さらに文字色も背景も白くなってしまうため、何も見えなくなります。また、キーボード部分とぴったりくっついてしまっていることもわかります。
続いて、先ほどの修正を行った場合、次のようになります。
| ライトモード | ダークモード |
|---|---|
|
|
closeButton.style = .plain とするとダークモードにも対応した文字色となります。
closeButton.style = .done のままだった場合は次のようになります。
closeButton.tintColor 設定なし |
closeButton.tintColor 設定あり |
|---|---|
|
|
Assets > AccencColor に設定されている色 (デフォルトは .systemBlue) |
文字色ではなく背景の色が変わる |
iOS 18以前では UIToolbar の tintColor は、常にcloseButton の文字の色を変えます。
iOS 26 からは、UIBarButtonItem.Style.plain を指定している場合には tintColor は文字色が変わり、UIBarButtonItem.Style.done (もしくはUIBarButtonItem.Style.prominent )では tintColor は背景色の色を変更させます。
toolbar.tintColor と closeButton.tintColor はどちらも同じ場所の色を指すため、次のような場合には背景色がピンクのボタンになります。(UIToolbar 上に複数 UIBarButtonItem が設定されている場合にはもちろん違います。)
closeButton.style = .done
toolbar.tintColor = .systemBlue
closeButton.tintColor = .systemPink
iOS 18以前では、スタイルが .done であれ .plain であれ文字色を変更するため、カスタマイズするには 条件分岐が必要となります。
今回、私たちのアプリでは常に暗い背景のデザインのため、closeButton.style = .done のまま closeButton.tintColor = .clear を設定しました。ライト/ダークモードの切り替えがある場合には真っ白になってしまうので注意が必要です。
おすすめは何も設定せずに、Assets > AccencColor に設定されている色(デフォルトは .systemBlue)を使うのがいいんじゃないかと思います。
iOS18 以前のデザインに寄せたい
ちなみに、今回のようにUIToolbar を AccessoryView として設定している場合は、 iOS 18 以前のデザインに寄せることは難しいと思います。
次のように、UIToolbar に背景を与え、バーのように表示させてみます。
// ツールバーの背景色を設定
toolbar.backgroundColor = .black
// Liquid Glass の背景を削除する
closeButton.hidesSharedBackground = true
// closeButton の文字色を変更するために設定
closeButton.style = .plain
// closeButton の文字色を白にする
closeButton.tintColor = .white
見えるかな。キーボードの上部自体が角丸なので、変な隙間が開いてしまうんですよね。 そのため、今回の用途では iOS18 以前のデザインが使えないことがわかります。
UIBarButtonItem の色の対応
iOS 26 だけに対応する場合には、先述しましたが、 UIBarButtonItem.Style.done ではなく、UIBarButtonItem.Style.prominent が利用できます。
ドキュメントを見てみると、iOS 26以降は .done は deprecated となります。(bordered は iOS 8.0 時点で非推奨です。)
また次のように .done は .prominent へ Rename となっています。iOS 18 以前で .done を使っていた場合には自動的に .prominent を使っていることになります。
extension UIBarButtonItem {
public enum Style : Int, @unchecked Sendable {
case plain = 0
@available(iOS 26.0, *)
case prominent = 2
@available(iOS, introduced: 2.0, deprecated: 8.0, renamed: "UIBarButtonItem.Style.plain")
case bordered = 1
@available(iOS, introduced: 2.0, deprecated: 26.0, renamed: "UIBarButtonItem.Style.prominent")
public static var done: UIBarButtonItem.Style { get }
}
}
先ほど UIToolbar の方で結構書いたので、ここでは改めてまとめを書いておきます。
| スタイル | iOS 18 以前の tintColor |
iOS 26 の tintColor |
|---|---|---|
UIBarButtonItem.Style.plain |
文字色 | 文字色 |
UIBarButtonItem.Style.prominent |
利用不能 | 背景色 |
UIBarButtonItem.Style.done |
文字色 | 背景色 |
UINavigationController の対応
UINavigationControllerでは基本的にあらゆる設定を外す処理を行います。
// 既存の設定
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.titleTextAttributes = [.foregroundColor: UIColor.white]
appearance.backgroundColor = .lightGray
navigationController?.navigationBar.standardAppearance = appearance
navigationController?.navigationBar.scrollEdgeAppearance = appearance
navigationController?.navigationBar.compactAppearance = appearance
この状態でビルドすると次のような見た目になります。FirstViewController -> SecondViewController へ遷移しています。
| iOS 18 (First) | iOS 18 (Second) | iOS 26 (First) | iOS 26 (Second) |
|---|---|---|---|
|
|
|
|
戻るボタンが随分と違います。また、NavigationBar の高さ自体もおそらく高くなっています。
iOS 26 では UINavigationBar はデフォルトの状態で使うことになりました。
if #unavailable(iOS 26) {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.titleTextAttributes = [.foregroundColor: UIColor.white]
appearance.backgroundColor = .lightGray
navigationController?.navigationBar.standardAppearance = appearance
navigationController?.navigationBar.scrollEdgeAppearance = appearance
navigationController?.navigationBar.compactAppearance = appearance
}
そのためこれらの設定は #unavailable を利用して、iOS 26 が使えない場合にのみ設定するようにしました。
本来はさらに下にコンテンツが潜り込むような対応をすると良いでしょう。(まだやってない)
余談
以前は次のように UINavigationBar の下線がでないようにして、バーの背景色を変更していました。
// ナビゲーションバーの背景色を透過する
navigationController.navigationBar.setBackgroundImage(UIImage(), for: .default)
// ナビゲーションバーの下線をなくす
navigationController.navigationBar.shadowImage = UIImage()
// ナビゲーションバーの背景色を変更する
navigationController.navigationBar.barTintColor = .lightGray
iOS 15 以後はナビゲーションバーは透過されているスタイルがデフォルトになります。
また現在、 navigationBar.barTintColor では背景色の変更はできないので注意してください。UINavigationBarAppearanceを使いましょう。
~~ちなみに私たちのアプリでは iOS 15 以後にデフォルトが透過された影響と、barTintColor を背景色と合わせていた理由で、iOS 15 でも特に問題なく動いちゃっていて、今も有効だと思っていました...。
背景色の透過と下線をなくす設定は standardAppearance と compactAppearance の状態では効いていないように見えますが、scrollEdgeAppearance の状態では効いているようです!スクロールしたら出てきちゃった!iOS 26 からは関係ないですが、iOS18 以前を使っている場合は、削除するだけじゃなく UINavigationBarAppearance をちゃんと使ったほうが良さそうですね。
WebView での UINavigationBar のバグ
iOS 26.0 〜 iOS 26.0.1 で起きていたバグになります。 次の画像のように、WebView のローディング後に UINavigationBar 上の UIBarButtonItem の色が変わってしまいます。
| WebView ロード前 | WebView ロード後 |
|---|---|
|
|
iOS 26 から UIButton.Configurationに .glass .prominentGlass .clearGlass .prominentClearGlass の4つが増えました。
今回のバグは、その .glass から .clearGlass に変わってしまうようなイメージです。(ちなみに UIBarButtonItem からは直接 UIButton.Configurationを使うことはできない)
このバグの厄介なところが、色が変わってしまった後は、他の画面に遷移した後もずっとこのままになってしまうところです。
この UINavigationBar 上のボタンのガラス感は、背景のコンテンツに合わせて自動で変わります。自分で制御する方法は現時点ではありません。
途方に暮れていましたが、iOS 26.1 ではこの問題は発生しなくなりました。
UINavigationBar 上のボタンの Liquid Glass を無効にする
UINavigationBar の上のボタンは UIBarButtonItem が使われているため、 ``
例えば、次のように UIMenu を利用した UIButton が設定されているとします。
let menuButton = UIButton()
var menuActions = [UIMenuElement]()
menuActions.append(UIAction(title: "メニュー1", image: nil, state: .on, handler: { _ in }))
menuActions.append(UIAction(title: "メニュー2", image: nil, state: .off, handler: { _ in }))
menuButton.menu = UIMenu(title: "メニュー", options: .displayInline, children: menuActions)
menuButton.showsMenuAsPrimaryAction = true
menuButton.setTitle("メニュー1", for: .normal)
// ナビゲーションバーの右側に配置
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: menuButton)
この時、iOS 18 と iOS 26 では次のように表示されます。
| iOS 18 | iOS 26 |
|---|---|
|
|
これは、UIButton 自体の Configuration を変更しても、ガラス部分は変わってくれません。
if #available(iOS 26, *) {
// 文字サイズはいい感じにあるので有効ではあるが、背景には影響なし
menuButton.configuration = .plain()
}
menuButton.configuration = .prominentGlass() に設定するとわかるように、2重になってしまいます。
UIBarButtonItem の hidesSharedBackground を使うことで解決できます。
let barButtonItem = UIBarButtonItem(customView: menuButton)
if #available(iOS 26, *) {
barButtonItem.hidesSharedBackground = true
}
navigationItem.rightBarButtonItem = barButtonItem
iOS 26 UIButton.Configuration 設定なし |
iOS 26 prominentGlass() |
|---|---|
|
|
「共有背景を隠す」という意味は、複数のボタンがあるときに背景が共有されることがあるということです。
- sharesBackground 背景を共有するかどうか
- デフォルトは
true
- デフォルトは
- hidesSharedBackground 共有背景を隠すかどうか
- デフォルトは
false
- デフォルトは
次のようなコードで検証しました。今回は1番右に配置される addButton で検証しました。
let addButton = UIBarButtonItem(barButtonSystemItem: .add, target: nil, action: nil)
let cameraButton = UIBarButtonItem(barButtonSystemItem: .camera, target: nil, action: nil)
let bookmarksButton = UIBarButtonItem(barButtonSystemItem: .bookmarks, target: nil, action: nil)
if #available(iOS 26, *) {
addButton.sharesBackground = true
addButton.hidesSharedBackground = true
}
navigationItem.rightBarButtonItems = [addButton, cameraButton, bookmarksButton]
例えば真ん中の .camera で sharesBackground = false にした場合は、それぞれが独立するようになります。
ただし、.save などの文字で表記されるものなどは背景は共有されません。主要なアクションボタンやテキスト付きシステムボタンは sharesBackground を用いても独立します。
let addButton = UIBarButtonItem(barButtonSystemItem: .add, target: nil, action: nil)
let cameraButton = UIBarButtonItem(barButtonSystemItem: .camera, target: nil, action: nil)
let bookmarksButton = UIBarButtonItem(barButtonSystemItem: .bookmarks, target: nil, action: nil)
let saveButton = UIBarButtonItem(barButtonSystemItem: .save, target: nil,
navigationItem.rightBarButtonItems = [addButton, cameraButton, bookmarksButton, saveButton]
並び順を次のようにすると次のようにグルーピングされます。
navigationItem.rightBarButtonItems = [addButton, cameraButton, bookmarksButton, saveButton]
並び順が少し変ですね。実際に動作して確認するのが大切そうです。
最後に、この hidesSharedBackground は backItem には適用できません。戻るボタンの Liquid Glass を無効にする方法は現在提供されていないようです。leftBarButtonItem を使うしかないですかね。
角丸対応
UICollectionView (.grouped つまりUITableView のようなスタイルを利用) の下にカスタムで角丸ボタンを置いていたのですが、そのボタンの角丸具合の調整をしました。
| iOS 18 以前 | iOS 26 |
|---|---|
|
|
とっても丸い。
おわりに
実際に行った対応は以上となります。さらっと書くつもりが、真面目に検証しながら書いてしまいました。
UIKitでの iOS 26 対応で1番よくまとまっていると感じた記事は What's New in UIKit です。大変助かりました。この記事では自分の影響範囲のみとなるので、是非こちらも参考にしてみてください。
個人的には以前のスタイルも選べるようになるといいな、とは思います。バナー広告との相性もすごく悪くなったと思うし、全てのアプリが Liquid Glass のデザインに向いているとは思えないし、デザインの差別化(必要なのかは置いておいて)も難しいですよね。
私のアプリでもほとんどが UITabbar や UINavigationController を使っているため、まだまだ今回の対応をする機会がありそうです。
ではでは。