💭

SwiftUIでViewの表示を操作するViewModifierを作る

2022/09/02に公開

概要

Viewを表示を条件によって分岐させるViewModifierを紹介します。
SwiftUIを使ってアプリを作るときに、ある条件によって表示するViewを変えたい時があります。
if 文を使用した方法とViewModifierを使用した方法を比較すると、ViewModiierを使うことのメリットを実感できると思います。

if 文を使用した方法

条件がtrueならばText(”True")を、falseならText("False")を表示したい時などです。
この時、単純にif 文を使って分岐させるコードが一般的のように思えます。
例として、if 文を使って条件分岐したViewにViewModifierを適用したい時を考えます。

if 文だけを使う

sstruct ContentView: View {
    @State var isShowView: Bool = true
    var body: some View {
        VStack {
            if isShowView {
                Text("True")
                    .font(.title)
            } else {
                Text("False")
                    .font(.title)
            }
            
            Button("Chage") {
                self.isShowView.toggle()
            }
            .buttonStyle(.bordered)
        }
    }
}

このコードには欠点があります。if 文を使用することで両方のViewに同じViewModifierを適用しようとすると、それぞれのViewに同じViewModifierを適用するか、全体をGroupで囲む必要があります。

Groupでif 文を囲む

struct ContentView: View {
    @State var isShowView: Bool = true
    var body: some View {
        VStack {
            Group {
                if isShowView {
                    Text("True")
                } else {
                    Text("False")
                }
            }
            .font(.title)
            
            Button("Chage") {
                self.isShowView.toggle()
            }
            .buttonStyle(.bordered)
        }
    }
}

Groupで囲むことによってViewModifierの適用はしやすくなり、if文だけの時よりは見やすくなりますが層が深くなってしまいました。
やりたいことは単純な処理にもかかわらず無駄に複雑になっています。

ViewModifierを使用した方法

ViewModifierを作成することでContentViewの構造がわかりやすくなります。

ViewModifierを使用した方法

struct ContentView: View {
    @State var isShowView: Bool = true
    
    var isHidden: Bool {
        !isShowView
    }
    
    var body: some View {
        VStack {
            Group {
                Text("True")
                    .modifier(HiddenViewModifier(isHidden: isHidden))
                
                Text("False")
                    .modifier(HiddenViewModifier(isHidden: !isHidden))
            }
            .font(.title)
            
            Button("Chage") {
                self.isShowView.toggle()
            }
            .buttonStyle(.bordered)
        }
    }
}

struct HiddenViewModifier: ViewModifier {
    let isHidden: Bool
    
    func body(content: Content) -> some View {
        if isHidden {
            EmptyView()
        } else {
            content
        }
    }
}

ViewModifierを使うとViewがif 文で途切れることがなくなり、ContentView全体の構造がわかりやすくなります。

Viewを拡張する方法

struct ContentView: View {
    @State var isShowView: Bool = true
    
    var isHidden: Bool {
        !isShowView
    }
    
    var body: some View {
        VStack {
            Group {
                Text("True")
                    .hiddenViewModifier(isHidden: isHidden)
                
                Text("False")
                    .hiddenViewModifier(isHidden: !isHidden)
            }
            .font(.title)
            
            Button("Chage") {
                self.isShowView.toggle()
            }
            .buttonStyle(.bordered)
        }
    }
}

struct HiddenViewModifier: ViewModifier {
    let isHidden: Bool
    
    func body(content: Content) -> some View {
        if isHidden {
            EmptyView()
        } else {
            content
        }
    }
}

extension View {
    func hiddenViewModifier(isHidden: Bool) -> some View {
        modifier(HiddenViewModifier(isHidden: isHidden))
    }
}

Viewを拡張することで作成したViewModifierの使用がもっと簡単になります。

まとめ

Viewを表示するか、表示しないかを管理したい場合はif 文だけではなくViewModifierを使った方がわかりやすくなります。作成したViewModifierをViewのextensionで使用することで簡単に使えるようにすることもできます。
一見コード量が増えて複雑になったようにも見えますが、見かけ上のコードの多さより構造のわかりづらさの方がデメリットが大きいです。再利用も簡単にできるのでぜひ使用してみることをお勧めします。

Discussion