
iOS 26からのLiquid Glassタブの実装を私もしたい
はじめに
スターバックス デジタルテクノロジー部のリルオッサです。
iOS 26がリリースされて、少しずつLiquid Glassに対応したiOSアプリが増えてきました。
Liquid Glassといえば、ナビゲーション周りでガラリとデザインが変わりましたが、まずはあのタブから実装方法を知りたいと思ったので記事にしてみることにしました。
環境
- Xcode 26.0.1
- iOS 26.0
Liquid Glass タブの実装
特別な実装は何も必要ありません。標準のタブを使用している場合、Xcode 26.0以降でビルドしたアプリは全てLiquid Glassのタブになります。
スクリーンショット
コード
import SwiftUI
struct ContentView: View {
var body: some View {
TabView {
Tab("Red", systemImage: "r.square.fill") {
Color.red
.ignoresSafeArea()
}
Tab("Yellow", systemImage: "y.square.fill") {
Color.yellow
.ignoresSafeArea()
}
Tab("Green", systemImage: "g.square.fill") {
Color.green
.ignoresSafeArea()
}
}
}
}
Liquid Glass タブにしたくない場合
info.plistにUIDesignRequiresCompatibility
というKeyを追加して、Bool値でYES
にすることで、一時的に以前のXcodeでビルドした時と同じ外観で表示されます。
スクリーンショット
注意点
この方法を使うと以前の外観でタブを表示できますが、Apple公式ドキュメントでは最新のデザインに移行するまでの一時的な措置として位置づけられています。
WWDC25: Platforms State of the Unionでも、このオプションが次のメジャーリリースで削除される予定ということを明言しています。
We intend this option to be removed in the next major release.
なので、この与えらた準備期間の中で新しいデザインに移行していきたいですね。
スクロールした時にタブを最小化する
こちらはiOS 26から登場したtabBarMinimizeBehavior(_:)
を使用することで、タブを特定の条件で最小化して、ユーザーがコンテンツにフォーカスを当てやすくなります。
デモ
下方向にスクロールした時にタブを最小化するようにしています。
コード
struct ContentView: View {
var body: some View {
TabView {
Tab("Red", systemImage: "r.square.fill") {
ScrollView {
ForEach(1..<100) {
Text("\($0)")
.frame(maxWidth: .infinity)
.font(.title)
}
}
.background(.red)
}
Tab("Yellow", systemImage: "y.square.fill") {
Color.yellow
.ignoresSafeArea()
}
Tab("Green", systemImage: "g.square.fill") {
Color.green
.ignoresSafeArea()
}
}
.tabBarMinimizeBehavior(.onScrollDown) // タブの最小化の設定
}
}
引数として、TabBarMinimizeBehavior
を渡しています。設定できる値は以下になります。
- automatic
- never
- onScrollDown
- onScrollUp
ハマった点
個人的にハマった点ですが、この.tabBarMinimizeBehavior(.onScrollDown)
ですが、ある程度のスクロール量を確保できないと機能しないような挙動になっていました。
例えば、スクロール内のコンテンツを減らした場合に下方向にスクロールはできるものの、タブが最小化されませんでした。
struct ContentView: View {
var body: some View {
TabView {
Tab("Red", systemImage: "r.square.fill") {
ScrollView {
ForEach(1..<41) {
Text("\($0)")
.frame(maxWidth: .infinity)
.font(.title)
}
}
.background(.red)
}
// ... 省略
検索タブを追加する
TabRole
を.search
のタブを追加することで検索タブを追加することができ、この検索タブは他のタブとは分離した形で表示されます。
任意のラベルを指定することもできますが、指定しない場合は虫眼鏡magnifyingglass
のアイコンになります。
スクリーンショット
コード
struct ContentView: View {
var body: some View {
TabView {
Tab("Red", systemImage: "r.square.fill") {
ScrollView {
ForEach(1..<41) {
Text("\($0)")
.frame(maxWidth: .infinity)
.font(.title)
}
}
.background(.red)
}
// ... 省略
// 検索タブ
Tab(role: .search) {
Color.white
}
}
.tabBarMinimizeBehavior(.onScrollDown)
}
}
検索バーを画面下部に表示させる
Tab(role: .search)
で表示するNavigationStack
下のViewでsearchable
を使用する場合、そのタブがタップされると検索バーが画面下部に表示されます。
デモ
コード
struct ContentView: View {
@State var searchText = ""
var body: some View {
TabView {
// ... 省略
Tab(role: .search) {
NavigationStack {
Color.white
.searchable(text: $searchText)
}
}
// ... 省略
}
}
タブの上にMusicアプリで見るようなViewを表示する
Apple標準のMusicアプリをみると、再生プレイヤーがタブの上に配置され、画面をスクロールするとタブと同列になって収まりのよい挙動をします。
似たような機能を実装をするには、tabViewBottomAccessory(content:)
を使用します。
このcontent
の中に表示したいViewを渡します。
デモ
すでにスクロールするとタブが最小化する機能を実装しているので、スクロールすると、タブが最小化され、タブと検索タブの間にHello, Liquid Glass!
と表示されたViewが移動します。
コード
struct ContentView: View {
@State var searchText = ""
var body: some View {
TabView {
// ... 省略
}
.tabBarMinimizeBehavior(.onScrollDown)
// ここを追加
.tabViewBottomAccessory {
Text("Hello, Liquid Glass!")
}
}
}
タブバーと並んだ時に表示を変更する
tabViewBottomAccessory
で表示したViewですが、タブの上部にある時は画面横いっぱいに表示されるのでスペースに困りませんが、タブと並ぶように配置された時はスペースに限りがあるので、表示の内容を変更したいという時があるかもしれません。
そんな時は、TabViewBottomAccessoryPlacement
の値をEnvironment
で取得できるので、その値を使用してViewの要素を調整できます。
デモ
今回は、タブバーと並んで表示された場合に文字をHello!
だけに変更しています。
コード
struct ContentView: View {
@State var searchText = ""
var body: some View {
TabView {
// ... 省略
}
.tabBarMinimizeBehavior(.onScrollDown)
.tabViewBottomAccessory {
// ここを変更
BottomAccessoryView()
}
}
}
struct BottomAccessoryView: View {
@Environment(\.tabViewBottomAccessoryPlacement) var placement
var body: some View {
switch placement {
case .inline:
Text("Hello!")
default:
Text("Hello, Liquid Glass!")
}
}
}
このTabViewBottomAccessoryPlacement
は、以下の2つのケースがあります。
expanded
- タブバー上に表示されている状態
inline
- タブに並んで表示されている状態
ただ、この@Environment(\.tabViewBottomAccessoryPlacement)
は、以下のようにオプショナルとなっているのでnil
の時の判定が必要となります。
extension EnvironmentValues {
/// The current placement of the tab view bottom accessory.
///
/// A `nil` value corresponds to an undefined placement.
public var tabViewBottomAccessoryPlacement: TabViewBottomAccessoryPlacement? { get }
}
おわりに
Apple標準アプリが採用されているタブ表現の実装方法を理解することができました。
世の中のiOSアプリが順次Liquid Glassに対応していくことで、Appleの目指すユーザー体験により近づいていくと考えているので一歩ずつ対応を進めていきたいですね。
Liquid Glass対応を楽しみましょう。