In SwiftUI, how to animate from an arbitrary corner radius to the corner radius of the display?

I am trying to implement a common UX/UI pattern: one view with rounded corners transitioning to a view that fills the screen (N.B. having the display's corner radius).

I got this to work if both corner radiuses are equal to that of the display (see first GIF).

However, I cannot seem to get it to work for arbitrary corner radiuses of the smaller view (i.e., the one that does not fill the screen).

I expected the be able to combine ContainerRelativeShape with .containerShape (see code), but this left me with a broken transition animation (see second GIF).

import SwiftUI

struct ContentView: View {
    @Namespace private var animation
    @State private var selectedIndex: Int?
    
    var body: some View {
        ZStack {
            if let selectedIndex = selectedIndex {
                ContainerRelativeShape()
                    .fill(Color(uiColor: .systemGray3))
                    .matchedGeometryEffect(id: "square-\(selectedIndex)", in: animation)
                    .ignoresSafeArea()
                    .onTapGesture {
                        withAnimation() {
                            self.selectedIndex = nil
                        }
                    }
                    .zIndex(1)
            }
            
            ScrollView {
                VStack(spacing: 16) {
                    ForEach(0..<20, id: \.self) { index in
                        if selectedIndex != index {
                            ContainerRelativeShape() // But what if I want some other corner radius to start with?
                                .fill(Color(uiColor: .systemGray5))
                                .matchedGeometryEffect(id: "square-\(index)", in: animation)
                                .aspectRatio(1, contentMode: .fit)
                                .padding(.horizontal, 12)
                                .onTapGesture {
                                    withAnimation() {
                                        selectedIndex = index
                                    }
                                }
                                // .containerShape(RoundedRectangle(cornerRadius: 20))
                                // I can add this to change the corner radius, but this breaks the transition of the corners
                        } else {
                            Color.clear
                                .aspectRatio(1, contentMode: .fit)
                                .padding(.horizontal, 12)
                        }
                    }
                }
                .padding(.vertical, 16)
            }
        }
    }
}

#Preview {
    ContentView()
}

What am I missing here? How can I get this to work? And where is the mistake in my reasoning?

Answered by coenbakker in 868030022

ConcentricRectangle

Thank you Reddit.

Accepted Answer

ConcentricRectangle

Thank you Reddit.

In SwiftUI, how to animate from an arbitrary corner radius to the corner radius of the display?
 
 
Q