SwiftUI:呈现具有从帧到帧的自定义转换的模态视图?

在使用 UIViewControllerTransitioningDelegateUIViewControllerAnimatedTransitioning 呈现 ViewController 时,我试图复制我以前在 UIKit 中所做的事情。

因此,例如,从如下所示的视图中:

SwiftUI:呈现具有从帧到帧的自定义转换的模态视图?

我想展示一个从视图 A 扩展到这个的视图(我会说是模态视图,但我不确定这是否是 SwiftUI 中处理它的正确方法):

SwiftUI:呈现具有从帧到帧的自定义转换的模态视图?

因此,我需要视图 B 从与视图 A 匹配的帧逐渐淡入到几乎全屏。这个想法是用户点击 A 就好像它想将其扩展到其详细信息(视图 B)一样。

我研究了 SwiftUI 转换,如下所示:

extension AnyTransition {
    static var moveAndFade: AnyTransition {
        let insertion = AnyTransition.move(edge: .trailing)
            .combined(with: .opacity)
        let removal = AnyTransition.scale
            .combined(with: .opacity)
        return .asymmetric(insertion: insertion,removal: removal)
    }
}

所以,我想我需要建立一个自定义过渡。但是,我不知道该怎么做,但我还是个新手。

我将如何建立一个过渡来处理所描述的案例?能够拥有一个 from frame 和一个 to frame...?

这是 SwiftUI 中正确的思考方式吗?

新信息:

我已经测试了 matchedGeometryEffect

示例:

struct TestParentView: View {
    
    
    @State private var expand = false
    @Namespace private var shapeTransition
    
    var body: some View {

        VStack {
            if expand {
         
                // Rounded Rectangle
                Spacer()
         
                RoundedRectangle(cornerRadius: 50.0)
                    .matchedGeometryEffect(id: "circle",in: shapeTransition)
                    .frame(minWidth: 0,maxWidth: .infinity,maxHeight: 300)
                    .padding()
                    .foregroundColor(Color(.systemGreen))
                    .animation(.easeIn)
                    .onTapGesture {
                        expand.toggle()
                    }
         
            } else {
         
                // Circle
                RoundedRectangle(cornerRadius: 50.0)
                    .matchedGeometryEffect(id: "circle",in: shapeTransition)
                    .frame(width: 100,height: 100)
                    .foregroundColor(Color(.systemOrange))
                    .animation(.easeIn)
                    .onTapGesture {
                        expand.toggle()
                    }
         
                Spacer()
            }
        }
    }

}

看起来 matchedGeometryEffect 可能是这项工作的工具。 但是,即使使用matchedGeometryEffect,我仍然无法解决这两件事:

  1. 如何加入淡入/淡出动画?
  2. 看看 matchedGeometryEffect 的行为,当我“关闭”视图 B 时,视图 B 立即消失,我们看到的动画是视图 A,从那里 B 回到视图 A 的原始帧。我实际上希望视图 B 在淡出时缩小到 A 所在的位置。
iCMS 回答:SwiftUI:呈现具有从帧到帧的自定义转换的模态视图?

您必须在要转换的两个视图上使用 .matchedGeometryEffect 修饰符。

这是一个例子:

struct MatchedGeometryEffect: View {
    
    @Namespace var nspace
    @State private var toggle: Bool = false
    
    var body: some View {
        HStack {
            if toggle {
                VStack {
                    Rectangle()
                        .foregroundColor(Color.green)
                        .matchedGeometryEffect(id: "animation",in: nspace)
                        .frame(width: 300,height: 300)
                    
                    Spacer()
                }
                
            }
            
            if !toggle {
                VStack {
                    
                    Spacer()
                    
                    Rectangle()
                        .foregroundColor(Color.blue)
                        .matchedGeometryEffect(id: "animation",in: nspace)
                        .frame(width: 50,height: 50)
                }
            }
        }
        .padding()
        .overlay(
        
            
            Button("Switch") { withAnimation(.easeIn(duration: 2)) { toggle.toggle() } }
            
        
        )
    }
}

enter image description here

图片应该是 GIF

使用此修饰符的主要两个部分是 idnamespace

您尝试匹配的两个视图的 id 必须相同。然后它们也必须在同一个命名空间中。命名空间使用 @Namespace 属性包装器在顶部声明。在我的示例中,我使用了“动画”,但它实际上可以是任何东西,最好是可以从其他类型的动画中唯一识别视图的东西。

另一个重要的信息是控制视图显示/隐藏的 '''@State''' 变量是动画的。这是通过使用 withAnimation { toggle.toggle() } 来完成的。

我对此也很陌生,因此有关更多信息,您可以阅读我从 Swift-UI 实验室找到的这篇文章:

https://swiftui-lab.com/matchedgeometryeffect-part1/

本文链接:https://www.f2er.com/132488.html

大家都在问