TLDR: how to render a whole subview before fading it in?
Consider this code snippet: a simple white view and a button that toggles an overlaying FrontView. The FrontView is a superposition of 2 black views, a fullscreen one and a smaller one.
struct ContentView: View {
@State private var frontViewIsOpen = false
var body: some View {
ZStack {
Color.white
.zIndex(0)
if frontViewIsOpen {
FrontView()
.transition(.opacity)
.zIndex(1)
}
VStack {
Spacer()
Button("Toggle") {
frontViewIsOpen.toggle()
}
}
.padding(.bottom, 50)
.zIndex(2)
}
.animation(.linear(duration: 1), value: frontViewIsOpen)
.ignoresSafeArea()
}
}
struct FrontView: View {
var body: some View {
Color.black
.overlay {
Color.black.frame(width: 100, height: 100)
}
}
}
On toggle, the FrontView fades in during 1 second. Here are the screenshots at t=0, t=0.5 and t=1:
During the whole animation, the inner 100pt black view is clearly visible. I guess SwiftUI not only fades-in the FrontView, but also all subviews in the tree. At t=0.5, the FrontView alpha is 0.5, the inner view is also 0.5, so with transparency, the intersection of both should be 0.75.
I recreated this test on UIKit. While fading-in/out a view, UIKit does not fade subviews automatically, resulting with a transition rendering like:
I'm trying to reproduce the UIKit transition behavior in SwiftUI. I tried to remove the inner views transaction animation with .transaction { $0.animation = nil }
, or to set to the inner view transition to .identity
, without success.
I there a way to render the whole subview before transitionning ?
Just add .compositingGroup
to FrontView
:
var body: some View {
Color.black
.overlay {
Color.black.frame(width: 100, height: 100)
}
.compositingGroup() // <- HERE
}