Sean Danzeiser
Sean Danzeiser

Reputation: 9243

Size a SwiftUI view to be safeAreaInsets.top + 'x'

I am trying to create a full bleed SwiftUI 'header' view in my scene. This header will sit within a List or a scrollable VStack.

In order to do this, I'd like to have my text in the header positioned below the safe area, but the full view should extend from the top of the screen (and thus, overlap the safe area). Here is visual representation:

V:[(safe-area-spacing)-(padding)-(text)]

here is my attempt:

struct HeaderView: View {

@State var spacing: CGFloat = 100

var body: some View {
    HStack {

        VStack(alignment: .leading) {

            Rectangle()
                .frame(height: spacing)
                .opacity(0.5)
            
            Text("this!").font(.largeTitle)
            Text("this!").font(.headline)
            Text("that!").font(.subheadline)
        }
        Spacer()
    }
    .frame(maxWidth: .infinity)
    .background(Color.red)
    .background(
        GeometryReader { proxy in
            Color.clear
                .preference(
                    key: SafeAreaSpacingKey.self,
                    value: proxy.safeAreaInsets.top
                )
        }
    )
    .onPreferenceChange(SafeAreaSpacingKey.self) { value in
        self.spacing = value
    }
}

}

This however, does not seem to correctly size 'Rectangle'. How can I size a view according to the safe area?

Upvotes: 0

Views: 869

Answers (2)

keyvan yaghoubian
keyvan yaghoubian

Reputation: 322

add an state to store desired height

@State desiredHeight : CGFloat = 0 then on views body :

    .onAppear(perform: {
        if let window = UIApplication.shared.windows.first{
            let phoneSafeAreaTopnInset = window.safeAreaInsets.top
            desiredHeight = phoneSafeAreaTopnInset + x
        }
    })

set the desiredHeight for your view .

.frame(height : desiredHeight)

Upvotes: 1

nicksarno
nicksarno

Reputation: 4245

Is this what you're looking for? I try to avoid using GeometryReader unless you really need it... I created a MainView, which has a background and a foreground layer. The background layer will ignore the safe areas (full bleed) but the foreground will stay within the safe area by default.

struct HeaderView: View {

    var body: some View {
        HStack {
            VStack(alignment: .leading) {
                Text("this!").font(.largeTitle)
                Text("this!").font(.headline)
                Text("that!").font(.subheadline)
            }
            Spacer(minLength: 0)
        }
    }
}

struct MainView: View {
    
    var body: some View {
        
        ZStack {
            
            // Background
            ZStack {
            }
            .frame(maxWidth:. infinity, maxHeight: .infinity)
            .background(Color.red)
            .edgesIgnoringSafeArea(.all)
            
            // Foreground
            VStack {
                HeaderView()
                Spacer()
            }
            
        }

    }
}

Upvotes: 1

Related Questions