Hey guys I have some issues with my code. I just experimented a bit with the matchedGeometryEffect in SwiftUI and it works great. But now I ran into some issues:
I cannot just deactivate the tabBar when the DetailView is dismissed because the view jumps up a bit.
The View transition is sometimes buggy and the console gives me (constantly) the output
Multiple inserted views in matched geometry group Pair<String, ID>(first: "bg", second: SwiftUI.Namespace.ID(id: 415)) have `isSource: true`, results are undefined.
Is there a better way to animate this smoothly and disable the tabBar?
Here is my code:
struct FullscreenView: View {
@Namespace var animationNamespace
@State var shouldShowFullsceen = false
@State var shouldShowDetails = false
var body: some View {
Input()
.padding()
.onTapGesture {
withAnimation(.interactiveSpring(
response: 0.6,
dampingFraction: 0.7,
blendDuration: 0.7
)) {
shouldShowFullsceen = true
}
}
.overlay {
if shouldShowFullsceen {
Output()
.onTapGesture {
withAnimation(.interactiveSpring(
response: 0.6,
dampingFraction: 0.7,
blendDuration: 0.7
)) {
shouldShowFullsceen = false
shouldShowDetails = false
}
}
}
}
}
}
extension FullscreenView {
@ViewBuilder
func Input() -> some View {
Content()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(BackgroundView())
}
@ViewBuilder
func Output() -> some View {
DetailedContent()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(FullscreenBackground())
}
}
extension FullscreenView {
@ViewBuilder
func Content() -> some View {
Image("dog")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(maxHeight: 300)
.matchedGeometryEffect(id: "content", in: animationNamespace)
}
}
extension FullscreenView {
@ViewBuilder
func DetailedContent() -> some View {
VStack {
Content()
ScrollView(.vertical) {
Text(dummyText)
.padding()
.opacity(shouldShowDetails ? 1 : 0)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.padding()
}
.transition(.identity)
.onAppear {
withAnimation(.interactiveSpring(
response: 0.6,
dampingFraction: 0.7,
blendDuration: 0.7
).delay(0.1)) {
shouldShowDetails = true
}
}
}
}
extension FullscreenView {
@ViewBuilder
func BackgroundView() -> some View {
Color.orange
.clipShape(RoundedRectangle(cornerRadius: 15))
.matchedGeometryEffect(id: "bg", in: animationNamespace)
}
}
extension FullscreenView {
@ViewBuilder
func FullscreenBackground() -> some View {
BackgroundView()
.ignoresSafeArea()
}
}
struct FullscreenView_Previews: PreviewProvider {
static var previews: some View {
FullscreenView()
}
}
Regarding the animation and console warning:
Don't overlay Output view. Show either the Input or the Output View with
if ... else
, then.matchedGeometryEffect
can do the transition.You should use
.matchedGeometryEffect
withisSource:
specified to true, for both image and background.get rid of
.transition(.identity)
.Here is the full code with comments: