Search code examples
if-statementswiftuisafearea

How to set "safeAreaInset" under a condition (if clause)


I am a beginner in Swift and I know this must have something to do with the "." just before "safeAreaInset". But even with "self" it doesn't work.

I want to activate the "safeAreaInset" only under an "if"-condition.

import SwiftUI
import MapKit

struct ContentView: View {
    var body: some View {
         Map()
             .safeAreaInset(edge: .top, alignment: .trailing) {
         Text("Hi!")
             .frame(maxWidth: .infinity, maxHeight: 80) // Breite und Höhe des Insets
             .background(.thinMaterial)
        }
    }
}

I read a lot today about "self.", but I assume that "self." is only to reference an instance and not a view? I also read something about extension of the view, but I am not sure if that would be the right (and for a beginner easiest) way. Or do I need perhaps a function for this?


Solution

  • Wrap an if around the contents of the safe area inset,

    @State var flag = false
    var body: some View {
        Map()
           .safeAreaInset(edge: .top, alignment: .trailing) {
               if flag {
                   Text("Hi!")
                       .frame(maxWidth: .infinity, maxHeight: 80)
                       .background (.thinMaterial)
               }
           }
    
        // just so you can toggle the flag and see the effect,
        Toggle("Toggle", isOn: $flag)
    }
    

    When flag is false, the safe area inset becomes an EmptyView, which is effectively the same as having no safe area inset at all.


    Note that it might be tempting to write such a modifier

    extension View {
        @ViewBuilder
        func `if`<V>(_ condition: Bool, @ViewBuilder content: (Self) -> V) -> some View where V : View {
            if condition {
                content(self)
            } else {
                self
            }
        }
    }
    

    and use it like this:

    Map()
        .`if`(flag) {
            $0.safeAreaInset(edge: .top, alignment: .trailing) {
                Text("Hi!")
                    .frame(maxWidth: .infinity, maxHeight: 80)
                    .background (.thinMaterial)
            }
        }
    

    It is important to note that this will not preserve view identity. It will destroy the Map and create a new Map every time the condition changes. This will cause the Map's state to be reset. For example, the camera position will be reset to the initial position.