7

有没有办法为新的全屏模式使用替代动画是 SwiftUI 中的 iOS 14?

目前它从底部向上滑动,但我想要交叉溶解。我尝试了几件事,但没有运气。我在想新的matchedGeometryEffect()修饰符可能有用。

下面是这个新特性的默认使用

struct ContentView: View {

    @State private var isShowing = false

    var body: some View {
        Button {
            isShowing.toggle()
        } label: {
            Text("Show Modal").font(.largeTitle)
        }.fullScreenCover(isPresented: $isShowing) {
            Text("Hello").font(.largeTitle)
        }
    }
}
4

3 回答 3

3

目前还没有直接的 API 来执行此操作,但您可以使用 ZStack 进行简单的 hack 来解决此问题

下面的代码作为替代代码工作得很好

@State var isPresented = false

var body: some View {
    
    ZStack {
        
        NavigationView {
            VStack {
                
                Button(action: {
                    // trigger modal presentation
                    withAnimation {
                        self.isPresented.toggle()
                    }
                    
                }, label: {
                    Text("Show standard modal")
                })
                
            }.navigationBarTitle("Standard")
        }
        
        ZStack {
            HStack {
                Spacer()
                VStack {
                    
                    HStack {
                        Button(action: {
                            // trigger modal presentation
                            withAnimation {
                                self.isPresented.toggle()
                            }
                            
                        }, label: {
                            Text("Dismiss")
                                .font(.headline)
                                .foregroundColor(.white)
                        })
                        Spacer()
                        
                        Image(systemName: "xmark.circle.fill")
                            .foregroundColor(.white)
                            .onTapGesture {
                                withAnimation {
                                    self.isPresented.toggle()
                                }
                        }
                    }
                    
                    
                        .padding(.top, UIApplication.shared.windows.filter{$0.isKeyWindow}.first?.safeAreaInsets.top)
                    Spacer()
                }
                Spacer()
            }
            
            
            
        }.background(Color.yellow)
            .edgesIgnoringSafeArea(.all)
            .offset(x: 0, y: self.isPresented ? 0 : UIApplication.shared.keyWindow?.frame.height ?? 0)
         
        
    }
    
}
于 2020-07-11T06:22:13.760 回答
0

下面的代码可以使用您所追求的matchedGeometryEffect()。

它现在是硬编码的,因为我还没有弄清楚如何从 List-> Detail 传递数据。如果你这样做,请告诉我!; )

import SwiftUI




struct Grid: View {
    
    let namespace: Namespace.ID
    
    var body: some View {
        
        List{
           Image("cover")
                .resizable()
                .frame(width: 50, height: 50)
                .cornerRadius(4)
                .padding()
                .matchedGeometryEffect(id: "animation", in: namespace)
            
            Image("cover2")
                 .resizable()
                 .frame(width: 50, height: 50)
                 .cornerRadius(4)
                 .padding()
                 .matchedGeometryEffect(id: "animation", in: namespace)
        }

   }
}

struct Detail: View {
    
    let namespace: Namespace.ID
    
    var body: some View {
        
            Image("cover")
                .resizable()
                .aspectRatio(contentMode: .fit)
                .cornerRadius(10)
                .padding(40)
                .matchedGeometryEffect(id: "animation", in: namespace)
        
      
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color(#colorLiteral(red: 0.234857142, green: 0.043259345, blue: 0.04711621255, alpha: 1)))
    }
}

struct ContentView: View {
    
    @Namespace private var ns
    @State private var showDetails: Bool = false
    
    var body: some View {
        ZStack {
            Spacer()
            if showDetails {
                Detail(namespace: ns)
            }
            else {
                Grid(namespace: ns)
            }
        }
        .onTapGesture {
            withAnimation(.spring()) {
                showDetails.toggle()
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
于 2021-05-07T07:51:53.173 回答
-2

因此,要回答您的问题,让我们先深入研究问题。

您需要使用与默认全屏封面不同的过渡来显示您的视图。如果是,那么这就是解决方案。

选项1:直截了当(适合初学者)

    struct ContentView: View {
    
    @State private var isShowing = false
    
    var body: some View {
        ZStack {
            if(!isShowing) {
                    Button {
                        withAnimation {
                        
                        isShowing.toggle()
                        }
                    } label: {
                        Text("Show Modal").font(.largeTitle)
                    }
            } else {
                VStack {
                Text("Hello").font(.largeTitle)
                    Button(action: {
                        withAnimation {
                        isShowing.toggle()
                        }
                    }) {
                        Text("Go back")
                    }
                }
                .frame(width: 400, height: 900) //recommended - adjust this frame size according to you dynamically
                .background(Color.red)
                .transition(.slide) // you can use other transition like .move ,etc.
            }
            
        }
    } }

选项 2:高级

  1. 将过渡添加到您的视图,并使此视图框架覆盖整个屏幕或您要覆盖的部分。要了解有关过渡的更多信息,请查看此处 - https://stackoverflow.com/a/62767038。您可以考虑创建自定义过渡。

  2. 将此自定义转换添加到您的视图中,条件如下

    struct ContentView: View {
    
    @State private var isShowing = false
    
    var body: some View {
        ZStack {
            if(!isShowing) {
                    Button {
                        withAnimation {
    
                        isShowing.toggle()
                        }
                    } label: {
                        Text("Show Modal").font(.largeTitle)
                    }
            } else {
                VStack {
                Text("Hello").font(.largeTitle)
                    Button(action: {
                        withAnimation {
                        isShowing.toggle()
                        }
                    }) {
                        Text("Go back")
                    }
                }
                .frame(width: 400, height: 900) //recommended - adjust this frame size according to you dynamically
                .background(Color.red)
                .transition(.rotate) //custom transition rotate from the link shared in 1st point. You can use inbuilt transition like .transition(.slide) and many more
            }
    
        }
    } }
    

在这里,我使用.rotate上面共享链接中的自定义动画,但您可以使用其他内置转换或根据您的要求进行自定义转换。

于 2020-07-07T14:54:06.397 回答