Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overlay view doesn't dismiss entirely in Swift UI

Tags:

ios

swift

swiftui

I'm showing an overlay to get the user's name on app launch; combined with a move from bottom transition, but the dismissing animation always stops at 90% and then disappears.

@ViewBuilder
func userNameOverlay() ->  some View {
    GroupBox {
        Image(systemName: "person.circle.fill")
            .font(.system(size: 60))
            .foregroundStyle(.colorTextPrimary)
            .padding()
        
        Text("Enter Your Name")
            .appTitle(withSpacing: true)
        
        TextField("John Doe", text: $username)
            .padding(12)
            .background(.colorBackground)
            .clipShape(.rect(cornerRadius: 16))
            .shadow(radius: 1, x: 1, y: 1)
            .padding(.bottom)
        
        Button {
            withAnimation {
                vm.showUserNameOverlay = false
            }
        } label: {
            Text("Save")
                .padding(.vertical, 10)
                .frame(maxWidth: .infinity)
                .background(.accent)
                .foregroundStyle(.colorBackground)
                .fontWeight(.bold)
                .clipShape(.rect(cornerRadius: 16))
        }
    }.padding(.horizontal)
        .groupBoxStyle(.customStyle)
        .transition(.move(edge: .bottom))
}

At first it was a vstack with an overlay, and now I've switched over to a zstack, but still not working, why is that?

            ZStack(alignment: .bottom) {
                ScrollView(showsIndicators: false) {
                    VStack {
                        main_views…
                    
                        Spacer()
                        
                    }.padding()
                        .foregroundStyle(.colorTextPrimary)
                        .blur(radius: vm.showUserNameOverlay ? 3 : 0)
                        .disabled(vm.showUserNameOverlay)
                }
                
                if vm.showUserNameOverlay {
                    Color.gray.opacity(0.4)
                        .ignoresSafeArea()
                    
                    userNameOverlay() // that’s the view I’m talking about
                        .zIndex(100)
                }
            }

and that's where it's called

video showing the issue

like image 609
Mark George Avatar asked Dec 14 '25 03:12

Mark George


1 Answers

This problem is being caused by the safe area inset.

The problem can be avoided by ignoring the bottom safe area inset for both the parent view and the overlay layer. However, this will probably mean, you will need to add bottom padding to both of the views, to keep their content out of the safe area.

A simpler workaround is to add top padding to the overlay, equivalent to the bottom safe area inset. This way, all that remains of the view before it disappears completely is the (invisible) padding.

The size of the inset can be found by wrapping the top-level parent view with a GeometryReader. If the top-level parent view is the ZStack then it works as follows:

GeometryReader { geo in
    ZStack(alignment: .bottom) {
        ScrollView(showsIndicators: false) {
            // ...
        }
        if vm.showUserNameOverlay {
            Color.gray.opacity(0.4)
                .ignoresSafeArea()

            userNameOverlay()
                .padding(.top, geo.safeAreaInsets.bottom) // 👈 here
                .zIndex(100)
        }
    }
    .animation(.easeInOut(duration: 2), value: vm.showUserNameOverlay)
}

Animation

like image 75
Benzy Neez Avatar answered Dec 15 '25 18:12

Benzy Neez



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!