Extending SwiftUI views beyond the safe area

Extending SwiftUI views beyond the safe area

iOS offers a safe area at the top and bottom of the screen. This safe area prevents content from touching notches present and helps developers place their views within the visible portion of the overall interface.

However, there are cases when we want to extend beyond this safe area. For example, when you want to create a custom navigation or a tab bar view or the time when you want a list of the content beyond the safe area.

Extending Colors Beyond the Safe Area

The first application to extend the content beyond a safe area is to extend colors to touch the safe areas to prevent glitched UI. For example, let's say you want to create a custom nav bar view. Let's build a view considering restrictions around the safe area.

struct CustomNavBarView: View {
    var body: some View {
        VStack {
            Text("Hello World")
                .frame(maxWidth: .infinity)
                .padding()
                .background(Color.pink.frame(maxWidth: .infinity))
            Spacer()
        }
    }
}

However, this does not look so good. Being the navigation bar, we want the background color to extend all the way to the top safe area. In order to make our views ignore safe areas in a particular direction, we can use the following iOS API on SwiftUI views.

This API allows us to specify the direction in which we want to ignore the safe area

At first instinct, we may use it directly on our content, which is a Text view.


var body: some View {
    VStack {
        Text("Hello World")
            .frame(maxWidth: .infinity)
            .padding()
            .background(Color.pink.frame(maxWidth: .infinity))
            .ignoresSafeArea(edges: .top)
        Spacer()
    }
}

Unfortunately, it pushes entire content beyond the safe area. Not something we want on our custom navbar view. All we want is only our color to extend beyond safe area boundaries. To fix this, we will make a small change.

Instead of applying ignoresSafeArea to Text, we will apply it to the background color. This will take background color all the way beyond the safe area but will keep the text out of it.


var body: some View {
    VStack {
        Text("Hello World")
            .frame(maxWidth: .infinity)
            .padding()
            .background(Color.pink.ignoresSafeArea(edges: .top))
            .frame(maxWidth: .infinity)
        Spacer()
    }
}

We can apply a similar effect when we want to add a custom tab bar at the bottom of the screen and we want colors to extend all the way beyond the bottom safe area.

The only change we need to do is to change ignoresSafeArea(edges: .top) to ignoresSafeArea(edges: .bottom) so that the background color of our view will ignore the bottom safe area.


var body: some View {
    VStack {
        Spacer()
        Text("Hello World")
            .frame(maxWidth: .infinity)
            .padding()
            .background(Color.pink.ignoresSafeArea(edges: .bottom))
            .frame(maxWidth: .infinity)
    }
}

Extending Views Beyond the Safe Area

Extending content beyond a safe area is not just limited to views. It applies to any content that inherits from type View. Let's say we want to add a Rectangle view to our screen. To create it, we will use a Rectangle constructor. To prove our point regarding the safe area, we will stretch it to the maximum in both horizontal and vertical directions.

This can be achieved by using .frame(maxWidth: .infinity, maxHeight: .infinity) on the created rectangle.


struct FullScreenView: View {
    var body: some View {
        VStack {
            Rectangle()
                .fill(Color.pink)
                .frame(maxWidth: .infinity, maxHeight: .infinity)
        }
    }
}

As you can see, although the rectangle has taken all available space in horizontal and vertical directions, it still leaves out some vertical space due to safe area. To extend it beyond top or bottom safe areas, we will again use the ignoresSafeArea API. Depending on whether we want to ignore top, bottom or vertical safe area, we will pass either .top, .bottom or .vertical values to edges parameter of ignoresSafeArea API.

💡
As a bonus, you can use .ignoresSafeArea() modifier on your view to ignore safe areas in all directions
💡
By default, safe areas also consider the area needed to display the keyboard. To ignore the keyboard safe area, you can use another view modifier .ignoresSafeArea(.keyboard) to ignore the safe area when the keyboard is active

Applications of Going Beyond the Safe Area in the App

There are a few scenarios where you want to extend beyond the safe area. As I mentioned earlier in this post, you may want to create a custom version of the navbar or tab bar. To mimic their standard appearance, you may want to use ignoresSafeArea API to extend beyond the safe area.

Another example is that you may want to use the full-screen loading indicator with transparent background and loading spinner. To give the impression that the full screen is loading, you may want to make the loading view the full screen by ignoring safe areas in all directions.

We can add an overlay of loading view over the main content while data is loading. We will customize the loading view to ignore the safe area in all directions so that it will appear as if taking the full space.


struct FullScreenLoadingView: View {
    var body: some View {
        Text("Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem")
            .padding()
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .overlay (
                ZStack {
                    Rectangle()
                        .fill(Color.gray.opacity(0.8))
                        .ignoresSafeArea(edges: .all)
                    ProgressView()
                        .progressViewStyle(
                            CircularProgressViewStyle(
                                tint: Color.white)
                        )
                        .padding()
                        .background(Color.black.opacity(0.4))
                        .cornerRadius(12)
                }
        )
    }
}
0:00
/

Conclusion

Safe areas help us place our views within the visible portion of the overall interface. However, there are cases when we want to extend our content beyond the safe area as we saw in this post. This post has got your back by explaining how you can extend your content and appearances such as colors beyond the safe area to create a delightful and consistent user experience.

I hope this article was useful in explaining the concepts behind the safe area and how to go beyond it. If you have any questions, comments, or concerns regarding this article, please feel free to reach out to me on Twitter @jayeshkawli

References

Add rich graphics to your SwiftUI app