Wednesday, January 10, 2024
HomeiOS Developmentios - Peak resetting to 0 first when utilizing a .matchedGeometryEffect() transition...

ios – Peak resetting to 0 first when utilizing a .matchedGeometryEffect() transition in SwiftUI


I am struggling to grasp why .matchedGeometryEffect() is behaving this manner:

I am attempting to animate a tab’s peak to completely different heights, primarily based on its content material. To take action I am utilizing .matchedGeometryEffect() on the tab background as observe:

struct ContentView: View {

    // MARK: - Properties
    @State personal var selectedTab: Tab = .cost
    @Namespace var namespace

    // MARK: - Physique
    var physique: some View {
        ZStack(alignment: .backside) {
            // Background coloration
            Colour.gray6
                .ignoresSafeArea()
            
            // Tab
            swap selectedTab {
            case .dashboard:
                DashboardTabView(namespace: namespace)
                
            case .transactions:
                TransactionsTabView(namespace: namespace)
                
            case .cost:
                PaymentTabView(namespace: namespace)
                
            case .providers:
                ServicesTabView(namespace: namespace)
                
            case .settings:
                SettingsTabView(namespace: namespace)
            }

        }
        .safeAreaInset(edge: .backside, spacing: 0) {
            // Tab bar
            TabBar(selectedTab: $selectedTab)
        }
    }
}

struct DashboardTabView: View {

    // MARK: - Properties
    let namespace: Namespace.ID
    
    // MARK: - Physique
    var physique: some View {
        TabViewContainer(namespace: namespace) {
            Textual content("Dashboard Tab")
                .foregroundStyle(.black)
        }
    }
}

struct PaymentTabView: View {

    // MARK: - Properties
    let namespace: Namespace.ID

    // MARK: - Physique
    var physique: some View {
        TabViewContainer(namespace: namespace) {
            HStack(spacing: 16) {
                CTAButton(title: "Obtain", icon: "arrow.down.sq.") { }
                    .matchedGeometryEffect(id: "one", in: namespace)
                CTAButton(title: "Pay", icon: "dollarsign.arrow.circlepath", coloration: Colour(hex: "#F1D302")) { }
                    .matchedGeometryEffect(id: "two", in: namespace)
            }
            .body(peak: 52)
            .padding(.horizontal)
        }
    }
}

struct TabViewContainer<Content material: View>: View {

    // MARK: - Init
    init(
        cornerRadii: RectangleCornerRadii = .init(topLeading: 21, bottomLeading: 0, bottomTrailing: 0, topTrailing: 21),
        namespace: Namespace.ID,
        @ViewBuilder content material: @escaping () -> Content material
    ) {
        self.cornerRadii = cornerRadii
        self.namespace = namespace
        self.content material = content material
    }

    // MARK: - Properties
    let namespace: Namespace.ID
    @State personal var childHeight: CGFloat = 0
    @ViewBuilder var content material: () -> Content material
    personal let cornerRadii: RectangleCornerRadii

    // MARK: - Physique
    var physique: some View {
        ZStack(alignment: .backside) {
            // Background coloration
            Colour.gray0
                .matchedGeometryEffect(id: "tab_background", in: namespace)
                .body(peak: childHeight)
                .clipShape(UnevenRoundedRectangle(cornerRadii: cornerRadii, fashion: .steady))
            
            // Content material
            content material()
                .padding(.vertical)
                .overlay {
                    GeometryReader { proxy in
                        Colour.clear
                            .activity(id: proxy.dimension.peak) {
                                childHeight = max(proxy.dimension.peak, 0)
                            }
                    }
                }
        }
    }
}

I can see the animation on the display nevertheless it seems to be like as an alternative of animating from the origin view to the vacation spot view immediately, it reset the peak to 0 first, inflicting the animation to interrupt.

Would anyone perceive why it is behaving this manner by any likelihood? Am I lacking one thing within the implementation?

This is what it seems to be like proper now. I slowed down the animation on Xcode simulator so you possibly can see it extra clearly:

Hyperlink to Xcode simulator demo

I am attempting to show some tabs primarily based on the selectedTab worth within the ContentView. These tabs (DashboardTabView, PaymentTabView, and so forth) all leverage the identical TabViewContainer that comprises a Colour.gray0 view that makes use of .matchedGeometryEffect(id: "tab_background", in: namespace).

My expectation is that these tab will transition peak seamlessly from one tab to a different, and actually after I arduous code the values for the peak the animation is working propertly.

The issue arises after I use GeometryReader to retrieve the peak of the content material() youngster view. Then the animation breaks.



Supply hyperlink

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments