Styling with Liquid Glass Availability
Tags: [Swift, Liquid Glass, Blog]
この記事はCYBOZU SUMMER BLOG FES ’25の記事です。
iOS26ではButton
やTextField
がLiquid Glassに対応するコンポーネントになりましたが、2025/10/03現在ではOSバージョンによる分岐が必要です。
しかしこの分岐はlayoutとstylingの問題で、SwiftUIコード上のセマンティックな部分は共通のため、View全体を分岐するのは避けたいところです。
この要求を満たすため、stylingの問題はView styleコードの中に押し込めると、既存のコードとも適合します。
TextFieldStyle
TextFieldStyle
はconfiguration
がそのままTextField
になっているため、シンプルです。
struct MyGlassTextFieldStyle: TextFieldStyle {
func _body(configuration: TextField) -> some View {
if #available(iOS 26.0, *) {
configuration
.padding(8)
.glassEffect()
} else {
configuration
.textFieldStyle(.roundedBorder)
}
}
}
ButtonStyle
ButtonStyle
はTextFieldStyle
より少し複雑です。
既存のボタンの多くはbuilt-inもしくはユーザー定義のButtonStyle
が活用されていると思いますが、configuration
はButtonStyleConfiguration
のため、TextFieldStyle
のようなstyleの中では適用されません。
@available(iOS 26.0, *)
struct MyGlassButtonStyle: ButtonStyle {
func makeBody(configuration: Self.Configuration) -> some View {
configuration.label
.padding(8)
.glassEffect()
}
}
MyGlassButtonStyle
は既存のButtonStyle
とはconcreteな型が異なるため、.buttonStyle()
内で呼び分けることはできません。ViewModifier
で分岐します。
struct MyGlassButton: ViewModifier {
var fallBack: FallBack
func body(content: Content) -> some View {
if #available(iOS 26.0, *) {
content
.buttonStyle(MyGlassButtonStyle())
} else {
content
.buttonStyle(.myButtonStyle)
}
}
}
extension View {
func myGlassButton() -> some View {
self.modifier(MyGlassButton())
}
}
これをButton
に適用します。
struct MyButton: View {
var body: some View {
Button("Tap me") { print("hello") }
.myGlassButton()
}
}
これらの対応でセマンティックな共通部分を持ちつつ、コンポーネントのスタイルを分岐できました。
OSバージョンによる分岐も既存のView Styles APIの形式を踏襲するとSwiftUIの世界に適合しやすい形で記述できます。
© 2025 La voix du code