ZStack in SwiftUI

DevTechie Inc
Jan 6, 2023

ZStack is used to layout a view that overlays its subviews, aligning them in z-axis. ZStack overlays its subviews by assigning each successive subview a higher z-axis value then the one before it. This means that at the end subviews appear on top of each other.

Let’s look at an example. We will create 10 cards stacked over each other using ZStack.

struct DevTechieZStack: View {
    let colors = [Color.pink, .purple, .red, .indigo, .mint, .orange, .blue, .cyan, .green, .teal]
    var body: some View {
        ZStack {
            ForEach(0..<colors.count, id: \.self) { idx in
                RoundedRectangle(cornerRadius: 20)
                    .fill(colors[idx])
                    .frame(width: 200, height: 200)
                    .shadow(radius: 5)
                    .offset(x: CGFloat(idx) * 10.0, y: CGFloat(idx) * 10.0)
            }
        }
    }
}

By default, ZStack aligns its views at the center but we can change the alignment by passing alignment value. Let’s update our example to include alignment.

struct DevTechieZStack: View {
    let colors = [Color.pink, .purple, .red, .indigo, .mint, .orange, .blue, .cyan, .green, .teal]
    let alignments = [Alignment.bottom, .center, .trailing, .bottomTrailing, .bottomLeading, .top, .topLeading, .topTrailing]
    
    @State private var currentAlignment = Alignment.center
    
    var body: some View {
        ZStack(alignment: currentAlignment) {
            ForEach(0..<colors.count, id: \.self) { idx in
                RoundedRectangle(cornerRadius: 20)
                    .fill(colors[idx])
                    .frame(width: 200 - CGFloat(idx) * 20.0, height: 200 - CGFloat(idx) * 20.0)
                    .shadow(radius: 5)
                    
            }
        }
        .onTapGesture {
            withAnimation {
                currentAlignment = alignments.randomElement()!
            }
        }
    }
}

ZStack is great to provide a background color or a background image for the view. We will use Color view for an example.

struct DevTechieZStack: View {
    var body: some View {
        ZStack {
            Color.orange
            
            VStack {
                Text("DevTechie.com")
                    .font(.largeTitle)
                    .foregroundColor(.white)
            }
        }
    }
}

Notice that the safeArea at the bottom and at the top is not covered by the background color. By default, safeArea is honored but we can change that with the help of .ignoresSafeArea() modifier.

struct DevTechieZStack: View {
    var body: some View {
        ZStack {
            Color.orange
            
            VStack {
                Text("DevTechie.com")
                    .font(.largeTitle)
                    .foregroundColor(.white)
            }
        }
        .ignoresSafeArea()
    }
}

ZStack is also useful to show view on top of another, for example popup views.

struct DevTechieZStack: View {
    
    @State private var showPopup = false
    
    var body: some View {
        ZStack {
            Color.orange
            
            VStack {
                Text("DevTechie.com")
                    .font(.largeTitle)
                    .foregroundColor(.white)
                
                Button {
                    withAnimation {
                        showPopup.toggle()
                    }
                } label: {
                    Label("Show message", systemImage: "quote.bubble")
                        .foregroundColor(.white)
                }
                .buttonStyle(.bordered)
            }
            
            if showPopup {
                VStack {
                    Text("Learning iOS Development?")
                        .font(.title)
                    Text("Visit DevTechie.com")
                        .font(.largeTitle)
                    
                    Button {
                        showPopup.toggle()
                    } label: {
                        Label("Close", systemImage: "xmark")
                            .foregroundColor(.white)
                    }
                    .buttonStyle(.bordered)
                }
                .padding()
                .background(.thickMaterial, in: RoundedRectangle(cornerRadius: 20))
            }
        }
        .ignoresSafeArea()
    }
}

Another use case for ZStack is to have a Fast Action Button(FAB) control on the view.


struct DevTechieZStack: View {
    
    let dtCourses = [
                    "Master SwiftUI 4 by Example",
                    "Build Photo Gallery App in SwiftUI",
                    "Introdution to MapKit in SwiftUI",
                    "Food Recipes app in SwiftUI",
                    "Machine Learning in iOS",
                    "Build Strava Clone in UIKit",
                    "Build DisneyPlus Clone in SwiftUI",
                    "Maps in SwiftUI",
                    "What's new in SwiftUI 4",
                    "Shoe Shopping app with Apple Pay in SwiftUI",
                    "Top Destinations App in SwiftUI",
                    "HealthKit integration in SwiftUI",
                    "Build DevTechie Video Course wth AVPlayer and SwiftUI",
                    "Let's Build Pantry App With Firebase and SwiftUI",
                    "iOS 15 Widgets using WidgetKit and SwiftUI",
                    "Goals app in SwiftUI and Firebase"
                        ]
    
    var body: some View {
        NavigationStack {
            ZStack(alignment: .bottomTrailing) {
                List(dtCourses, id: \.self) { course in
                    Text(course)
                        .font(.title3)
                }
                
                Button {
                    print("Button pressed")
                } label: {
                    Image(systemName: "plus.circle.fill")
                        .resizable()
                        .frame(width: 50, height: 50)
                }
                .padding([.trailing, .bottom], 10)
            }
            .navigationTitle("DevTechie Courses")
        }
    }
    
}
With that we have reached the end of this article. Thank you once again for reading. Don’t forget to follow 😍. Also subscribe our newsletter at https://www.devtechie.com