在复杂UI中使用SwiftUI的MatchedGeometryEffect [英] Using SwiftUI's matchedGeometryEffect in complex UI

查看:57
本文介绍了在复杂UI中使用SwiftUI的MatchedGeometryEffect的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的应用程序中,我想在卡片和全屏覆盖之间创建一个‘英雄’动画,matchedGeometryEffect似乎很适合。然而,无论我尝试什么,我都无法让动画像预期的那样工作,而且它看起来一点也不像通常的matchedGeometryEffect动画。Here's它目前看起来是什么样子。这就是我目前所拥有的:(抱歉,代码太多了,但这是必要的,因为对于简单的视图来说,它工作得很好)

Something.swft

struct Something: Identifiable {
    let id = UUID()
    let image: Image
}

ContentView.swft

struct ContentView: View {
    @Namespace var namespace
    
    let items: [Something] = [
        Image("a"), Image("b")
    ].map { Something(image: $0 )}
    
    @State var selectedItem: Something?

    var body: some View {
        ZStack {
            VStack {
                ScrollView {
                    VStack(alignment: .leading) {
                        ForEach(items) { item in
                            CardView(
                                image: item.image,
                                namespace: namespace,
                                isSource: self.selectedItem == nil,
                                id: item.id
                            )
                            .background(Color.white)
                            .contentShape(RoundedRectangle(cornerRadius: 16, style: .continuous))
                            .zIndex(1)
                            .onTapGesture {
                                withAnimation(.spring()) {
                                    self.selectedItem = item
                                }
                            }
                        }
                    }
                }
            }
            .overlay(EmptyView())
            
            if let item = selectedItem {
                EventView(
                    image: item.image
                ) {
                    self.selectedItem = nil
                }
                .matchedGeometryEffect(id: item.id, in: namespace, isSource: false)
                .zIndex(2)
            }
        }
        .animation(.spring())
        .transition(.scale)
    }
}

CardView.wift

struct CardView: View {
    let image: Image
    let namespace: Namespace.ID
    let isSource: Bool
    let id: UUID

    var body: some View {
        VStack(alignment: .leading) {
            ZStack(alignment: .bottomTrailing) {
                image
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .frame(height: 225)
                    .clipShape(RoundedRectangle(cornerRadius: 12, style: .continuous))
                    .matchedGeometryEffect(id: id, in: namespace, isSource: isSource)
            }
        }
    }
}

EventView.swft

struct EventView: View {
    let image: Image
    let onDismiss: () -> Void
        
    var body: some View {
        image
            .resizable()
            .aspectRatio(contentMode: .fill)
            .edgesIgnoringSafeArea(.all)
            .onTapGesture(perform: onDismiss)
    }
}

如有任何关于如何添加或更改以使其正常工作的建议,我们将不胜感激,谢谢!

推荐答案

我针对相同的需求所做的是将properties: .position添加到matchedGeometryEffect。然后,您需要指定如何从一个视图(比方说,缩略图卡片视图)转换到另一个(比方说,全屏卡片视图)。这是通过自定义转换实现的,如下所示:

extension AnyTransition
    {
    // This transition will pass a value (0.0 - 1.0), indicating how much of the
    // transition has passed. To communicate with the view, it will
    // use the custom environment key .modalTransitionPercent
    // it will also make sure the transitioning view is not faded in or out and it
    // stays visible at all times.
    static var modal: AnyTransition
        {
        AnyTransition.modifier(active: ThumbnailExpandedModifier(pct: 0), identity: ThumbnailExpandedModifier(pct: 1))
        }

    struct ThumbnailExpandedModifier: AnimatableModifier
        {
        var pct: CGFloat
        
        var animatableData: CGFloat
            {
            get { pct }
            set { pct = newValue }
            }

        func body(content: Content) -> some View
            {
            return content
                .environment(.modalTransitionPercent, pct)
                .opacity(1)
            }
        }
  }

extension EnvironmentValues
    {
    var modalTransitionPercent: CGFloat
        {
        get { return self[ModalTransitionKey.self] }
        set { self[ModalTransitionKey.self] = newValue }
        }
    }

public struct ModalTransitionKey: EnvironmentKey
    {
    public static let defaultValue: CGFloat = 0
    }

这篇关于在复杂UI中使用SwiftUI的MatchedGeometryEffect的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆