SwiftUI 条件付きモディファイア
SwiftUI では条件に応じて異なるモディファイアを適用したい場面がある。しかし、実装方法によっては予期しない問題が発生することもある。条件付きモディファイアの正しいアプローチを理解しておこう。
三項演算子を使う方法(推奨)
最もシンプルで安全な方法は、三項演算子でプロパティの値を切り替えることだ。
Text("Hello")
.foregroundColor(isHighlighted ? .red : .primary)
.fontWeight(isImportant ? .bold : .regular)
.padding(isExpanded ? 20 : 10)この方法はビューの型が変わらないため、SwiftUI の差分検出が正しく機能し、アニメーションも期待通りに動作する。
if 文で分岐する方法(注意が必要)
if 文を使ってモディファイアを条件分岐させることもできるが、注意が必要だ。
// 問題のあるパターン
var body: some View {
if isSpecial {
Text("Hello")
.foregroundColor(.red)
.bold()
} else {
Text("Hello")
.foregroundColor(.primary)
}
}この書き方では、isSpecial が変わるたびにビュー全体が再生成される。SwiftUI は 2 つの Text を同一のビューと認識しないため、アニメーションが途切れたり、状態がリセットされたりする可能性がある。
AnyView を避ける
型消去のために AnyView を使う方法は、パフォーマンス上の問題があり推奨されない。
// 避けるべきパターン
func styledText() -> AnyView {
if isSpecial {
return AnyView(Text("Hello").bold())
} else {
return AnyView(Text("Hello"))
}
}AnyView は SwiftUI の型システムを迂回するため、差分検出が非効率になる。
View extension で条件付きモディファイアを作る
条件付きでモディファイアを適用する extension を作る方法がある。
extension View {
@ViewBuilder
func `if`<Content: View>(
_ condition: Bool,
transform: (Self) -> Content
) -> some View {
if condition {
transform(self)
} else {
self
}
}
}Text("Hello")
.if(isHighlighted) { view in
view.foregroundColor(.red).bold()
}ただし、この方法も内部で型が変わるため、三項演算子ほど安全ではない。単純なプロパティ変更には三項演算子を使い、複雑な条件分岐にのみこのパターンを使うのがよい。
オプショナル値への対応
オプショナルな値に基づいてモディファイアを適用する場合。
extension View {
@ViewBuilder
func ifLet<Value, Content: View>(
_ value: Value?,
transform: (Self, Value) -> Content
) -> some View {
if let value = value {
transform(self, value)
} else {
self
}
}
}Text("商品名")
.ifLet(discountRate) { view, rate in
view.overlay(
Text("-\(rate)%")
.font(.caption)
.foregroundColor(.red),
alignment: .topTrailing
)
}条件付き装飾の実践パターン
.foregroundColor(condition ? .red : .blue) のように三項演算子を使う。最も安全で効率的。
ViewModifier を作成し、内部で条件分岐する。モディファイアの型は常に同じに保たれる。
@ViewBuilder を使った extension を検討。ただし、アニメーションへの影響を確認すること。
条件付き ViewModifier の例
struct ConditionalBorderModifier: ViewModifier {
var showBorder: Bool
var color: Color
func body(content: Content) -> some View {
content
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(showBorder ? color : Color.clear, lineWidth: 2)
)
}
}
extension View {
func conditionalBorder(_ show: Bool, color: Color = .blue) -> some View {
modifier(ConditionalBorderModifier(showBorder: show, color: color))
}
}モディファイア内で条件を処理することで、ビューの型を変えずに条件付きの装飾を実現できる。これが最も SwiftUI らしいアプローチであり、状態変化時のアニメーションも自然に動作する。











