Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use edgesIgnoringSafeArea in SwiftUI, but make a child view respect the safe area?

Tags:

ios

swiftui

I'm building a UI is SwiftUI with a list view, and I want to put a panel over part of the list view with a button on it.

On devices with a safe area at the bottom (that don't have a physical home button) I want the panel to go to the bottom of the screen. But I want to make sure that the button on the panel doesn't extend into the safe area.

In my example code, the HStack is the panel that contains the button. I tried adding .edgesIgnoringSafeArea(.bottom) to it, but that doesn't allow it to extend to the bottom. This is kind of confusing to me, because the List that's in the same ZStack extends into the bottom safe area.

When I add .edgesIgnoringSafeArea(.bottom) to the ZStack, the HStack (blue panel) is allowed to extend into the safe area at the bottom of the screen. This is what I want, but then once I do that, how can I tell the Button that's a child of the HStack to not ignore the safe area?

I know how I would do this in UIKit, but I'm really hoping to be able to build this UI in SwiftUI. I could manually add some padding or Spacers to add extra padding under the Button to account for the safe area, but then there would be extra spacing on devices with a home button that don't have a bottom safe area. I'd like to figure out an elegant solution where I can rely on the system to define its safe areas instead of manually defining any spacing numerically or creating conditional situations for different devices.

struct ContentView: View {
    var body: some View {

        ZStack(alignment: .bottom) {

                    List {
                        Text("Item 1")
                        Text("Item 2")
                        Text("Item 3")
                    }

                    HStack {
                        Spacer()
                        Button(action: {
                            // do something
                        }){
                            Text("Button")
                                .font(.title)
                                .padding()
                                .background(Color.green)
                                .foregroundColor(.white)
                                .cornerRadius(15)
                        }.padding()
                        Spacer()
                    }.background(Color.blue).edgesIgnoringSafeArea(.bottom)
                }
    }
}

screenshot of a failed attempt at what I want

like image 723
gohnjanotis Avatar asked Mar 13 '20 20:03

gohnjanotis


People also ask

How do I ignore top safe area in SwiftUI?

So, to summarize, ignoring safe areas in SwiftUI is just a matter of calling a simple view modifier. Apply it whenever necessary, and expand the safe area of your views in order build an interface the way you like it.

Why is edgesignoringsafearea not working in SwiftUI?

Depending on the surrounding view hierarchy, SwiftUI may not honor an edgesIgnoringSafeArea (_:) request. This can happen, for example, if the view is inside a container that respects the screen’s safe area. In that case you may need to apply edgesIgnoringSafeArea (_:) to the container instead.

How to ignore safe areas in SwiftUI?

So, to summarize, ignoring safe areas in SwiftUI is just a matter of calling a simple view modifier. Apply it whenever necessary, and expand the safe area of your views in order build an interface the way you like it. If you found this post useful then please consider sharing it!

Is it possible to use edgesignoringsafearea on a parent view?

It is an EdgeInsets. This doesn't work if you use .ignoresSafeArea on a parent view. Show activity on this post. If you use edgesIgnoringSafeArea on an parentView and you want to access the device UISafeAreaInsets you can do the following:

How do I ignore all edges of a safe area?

See that the top and bottom edges of the safe area remain unaffected. To change that, we can use the ignoresSafeArea view modifier: The above modifier returns a new view that ignores all safe area edges and expands to all directions. And it’s all we need to do the trick!


4 Answers

Whatever view you draw in the background modifier will use the frame of the view it's modifying. So you need to tell THAT view to ignore the safe area.

.background(Color.blue.edgesIgnoringSafeArea(.bottom))
like image 60
Joe Susnick Avatar answered Oct 18 '22 19:10

Joe Susnick


You can access the height of the safe area using a GeometryReader. Then you could use the height of the safe area as bottom padding or offset on your button.
https://developer.apple.com/documentation/swiftui/geometryproxy

struct ContentView: View {
    var body: some View {

        GeometryReader { proxy in
            ZStack(alignment: .bottom) {

                List {
                    Text("Item 1")
                    Text("Item 2")
                    Text("Item 3")
                }

                HStack {
                    Spacer()
                    Button(action: {
                        // do something
                    }){
                        Text("Button")
                            .font(.title)
                            .padding()
                            .background(Color.green)
                            .foregroundColor(.white)
                            .cornerRadius(15)
                    }
                    .padding(.bottom, proxy.safeAreaInsets.top)
                    Spacer()
                }.background(Color.blue)
            }.edgesIgnoringSafeArea(.bottom)
        }
    }
}
like image 38
KevinP Avatar answered Oct 18 '22 20:10

KevinP


edgesIgnoringSafeArea(_:) is Deprecated

use the following:


.background(Color.blue.ignoresSafeArea(edges: .bottom))
like image 5
Rajnish Raj Avatar answered Oct 18 '22 20:10

Rajnish Raj


Adding on to @Joe Susnick's answer, the full code is:

VStack {

}.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color(red: 0.357, green: 0.784, blue: 0.016, opacity: 0.5).ignoresSafeArea()
)

Anything inside of VStack respects the safe area whereas the background fills the whole screen.

like image 2
C.J. Windisch Avatar answered Oct 18 '22 20:10

C.J. Windisch