SwiftUI

SwiftUI动画 GeometryEffect

import SwiftUI

struct BusinessCardView: View {
    @State private var  flipped = false
    @State private var  animate3d = false
    var body: some View {
        VStack{
            Spacer()
            ZStack{
                FrontCard().opacity(flipped ? 0.0:1.0)
                BackCard().opacity(flipped ? 1.0:0.0)
            }
            .modifier(FlipEffect(flipped: $flipped, axis: (x:0,y:1), angle: animate3d ? 180:0))
            .onTapGesture {
                withAnimation(Animation.linear(duration: 0.8)) {
                    self.animate3d.toggle()
                }
            }
            Spacer()
        }.padding()
    }
}

struct FlipEffect: GeometryEffect {
    @Binding var flipped: Bool
    let axis: (x:CGFloat,y:CGFloat)
    var angle: Double
    
    var animatableData: Double {
        get {
            angle
        }
        set {
            angle = newValue
        }
    }
    func effectValue(size: CGSize) -> ProjectionTransform {
        DispatchQueue.main.async {
            self.flipped = self.angle >= 90 && self.angle < 270
        }
        let tweakAngle = flipped ? -180 + angle :angle
        let a = CGFloat(Angle(degrees: tweakAngle).radians)
        
        var tranform3d = CATransform3DIdentity
        tranform3d.m34 = -1/max(size.width, size.height)
        tranform3d = CATransform3DRotate(tranform3d,a,axis.x,axis.y,0)
        tranform3d = CATransform3DTranslate(tranform3d, -size.width/2.0, -size.height/2.0, 0)
        let affineTransform = ProjectionTransform(CGAffineTransform(translationX: size.width/2.0, y: size.height/2.0))
        return ProjectionTransform(tranform3d).concatenating(affineTransform)
    }
    
}

struct BackCard: View {
    var body: some View {
        HStack{
            VStack{
                VStack(alignment: .leading){
                    HStack{
                        Image(systemName: "person.circle").foregroundColor(.white).font(.title)
                        Text("DevTechie Interactive")
                            .font(.title)
                            .foregroundColor(.white)
                    }
                    HStack{
                        Image(systemName: "phone.circle").foregroundColor(.white).font(.subheadline)
                        Text("1234-1224-3234")
                            .font(.subheadline)
                            .foregroundColor(.white)
                    }
                    HStack{
                        Image(systemName: "mappin.circle").foregroundColor(.white).font(.subheadline)
                        Text("United States")
                            .font(.subheadline)
                            .foregroundColor(.white)
                    }
                }
            }.background(Capsule().frame(height:200).frame(minWidth:500).offset(x:-10))
            
            VStack{
                CircularImage(img: "bg1")
            }.padding(.trailing,20)
        }.frame(width:400,height: 200)
            .background(Color.orange)
        .cornerRadius(20)
        .shadow(radius: 10)
        
    }
    
}




struct FrontCard: View {
    var body: some View {
        VStack{
            Spacer()
            HStack{
                CircularImage(img: "bg1")
                VStack{
                    Text("DevTechie Interactive")
                        .font(.title)
                        .foregroundColor(.white)
                    HStack {
                        Image(systemName: "envelope")
                            .foregroundColor(.white)
                        Text("DevTechie@Interactive.com")
                            .font(.subheadline)
                            .foregroundColor(.white)
                    }
                }.padding()
                    .background(Capsule().frame(width:400).offset(x:50))
            }
            Spacer()
            Text("www.DevTechie.com")
                .foregroundColor(.white)
                .frame(maxWidth: .infinity)
                .background(Color.black)
            }.frame(width:400,height: 200)
            .background(Color.orange)
        .cornerRadius(20)
        .shadow(radius: 10)
    }
}

struct CircularImage: View {
    var img:String
    var body: some View {
        Image(img)
        .resizable()
            .frame(width: 100, height: 100)
        .clipShape(Circle())
            .overlay(Circle().stroke(Color.white, lineWidth: 3))
        .shadow(radius: 9)
    }
}