I'm implementing custom menu view with transition appearance from top trailing position. I'm using matchedGeometryEffect
on views background. The problem is with child views of second view. They appears before animation ends. You can see below:
How synchronize these button views with animation of parent view?
Below my code:
struct ContentView: View {
@State var show = false
@Namespace var namespace
var body: some View {
VStack(spacing: 0) {
HStack(spacing: 0) {
Spacer()
Button(action: {
withAnimation(.linear(duration: 1.2)) { // Longer duration for demo of issue
show.toggle()
}
}) {
Image(systemName: "ellipsis.circle")
.font(.title3)
.background( !show ?
Color.clear
.matchedGeometryEffect(id: "topMenuToggle", in: namespace, properties: .position)
: nil
)
}
}
.padding()
Color.clear
.overlay(
show ? MenuView(namespace: namespace) : nil
, alignment: .topTrailing
)
}
.foregroundColor(.white)
.background(Color.black.ignoresSafeArea())
}
}
struct MenuView: View {
let namespace: Namespace.ID
var body: some View {
VStack(spacing: 0) {
Button(action: {
}) {
HStack(spacing: 0) {
Text("Save video")
.font(.body)
Spacer(minLength: 0)
Image(systemName: "arrow.down.circle")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(height: 20)
}
}
.padding(.top, 18)
.padding(.bottom, 18)
.padding(.horizontal, 14)
Rectangle()
.fill(Color.white.opacity(0.1))
.frame(maxWidth: .infinity, maxHeight: 1)
Button(action: {
}) {
HStack(spacing: 0) {
Text("Report")
.font(.body)
Spacer(minLength: 0)
Image(systemName: "exclamationmark.bubble")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(height: 20)
}
}
.padding(.top, 16)
.padding(.bottom, 18)
.padding(.horizontal, 14)
}
.foregroundColor(.white)
.frame(width: 250)
.background(
Color.white.opacity(0.2)
.matchedGeometryEffect(id: "topMenuToggle", in: namespace, anchor: .bottomLeading)
)
.cornerRadius(12)
}
}