swiftui跳转页面,matchedGeometryEffect创建平滑过渡

           matchedGeometryEffect是SwiftUI提供的一个强大的工具,它能够在视图层次结构中不同位置的视图之间创建平滑的动画过渡。
  • 1、id:用于唯一标识匹配的视图。只有当两个视图使用相同的id时matchedGeometryEffect才能在它们之间创建动画过渡。

  • 2、namespace:命名空间,用于将不同视图的动画过渡关联起来。确保只有标记了相同命名空间的视图之间才会应用动画效果。

import SwiftUI

// Model Data

struct CatModel: Identifiable {
    var id = UUID().uuidString
    var image: String
    var title: String
    var price: String
}

var cats = [
    CatModel(image: "cat1", title: "cat1", price: "$100"),
    CatModel(image: "cat2", title: "cat2", price: "$200"),
    CatModel(image: "cat3", title: "cat3", price: "$300"),
    CatModel(image: "cat4", title: "cat4", price: "$400"),
    CatModel(image: "cat5", title: "cat5", price: "$500"),
    CatModel(image: "cat6", title: "cat6", price: "$600"),
]

// Scrolling Tab Button
var CatTabs = ["cat1","cat2","cat3","cat4"]
import SwiftUI

struct CatView: View {
    var catData: CatModel
    var animation: Namespace.ID
    
    var body: some View {
      
        VStack(alignment: .leading, spacing: 6) {
            
            ZStack {
                // both color and image are same name
                Color(catData.image)
                    .cornerRadius(15)
                
                Image(catData.image)
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .padding(20)
                    .matchedGeometryEffect(id: catData.image, in: animation)
  
            }
            
            Text(catData.title)
                .fontWeight(.heavy)
                .foregroundColor(.gray)
            
            Text(catData.price)
                .fontWeight(.heavy)
                .foregroundColor(.black)
        }
    }
}
import SwiftUI

struct CatTabButton: View {
    var title: String
    @Binding var selectedCat: String
    var animation: Namespace.ID
    
    var body: some View {
      
        Button {
            
            withAnimation(.spring()) {
                selectedCat = title
            }
        }label: {
            
            VStack(alignment: .leading, spacing: 6) {
                Text(title)
                    .fontWeight(.heavy)
                    .foregroundColor(selectedCat == title ? .black : .gray)
                
                if selectedCat == title {
                    
                    Capsule()
                        .fill(Color.black)
                        .frame(width: 40, height: 4)
                        .matchedGeometryEffect(id: "Tab", in: animation)
                }
            }
            .frame(width: 100)
        }
        
        
    }
}
import SwiftUI

struct ColorButton: View {
    var color: Color
    @Binding var selectedColor: Color
    
    var body: some View {
      
        ZStack {
            
            Circle()
                .fill(color)
                .frame(width: 20, height: 20)
            
            Circle()
                .stroke(Color.black.opacity(selectedColor == color ? 1 : 0), lineWidth: 1)
                .frame(width: 30, height: 30)
        }
        .onTapGesture {
            
            withAnimation {
                selectedColor = color
            }
        }
    }
}
import SwiftUI

struct CustomCorner: Shape {
    
    func path(in rect: CGRect) -> Path {
         
        let path = UIBezierPath(roundedRect: rect, byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: 35, height: 35))
        
        return Path(path.cgPath)
    }
}
  1. 1、定义 CustomCorner 结构:struct CustomCorner: Shape:定义一个名为CustomCorner 的结构体,并声明它遵循 Shape 协议。此协议要求实现 path(in:) 方法。

  2. 2、实现 path(in:) 方法:func path(in rect: CGRect) -> Path:这个方法接收一个 CGRect 参数,表示要绘制形状的区域,并返回一个 Path 对象。

  3. 3、使用 UIBezierPath 创建一个圆角矩形: let path = UIBezierPath(roundedRect: rect, byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: 35, height: 35))

    • (1)cornerRadii:CGSize(width: 35, height: 35):设置圆角半径,宽度和高度均为 35 点。

    • (2)byRoundingCorners: [.topLeft, .topRight]:指明哪些角需要圆角处理。在这里,只有左上角和右上角会被圆角化。

    • (3)roundedRect: rect:指定矩形的边界。

  4. 4、返回 Path: return Path(path.cgPath):将 UIBezierPath 转换为 SwiftUI 的 Path 类型并返回。这样就可以在 SwiftUI 中使用这个自定义形状。

import SwiftUI

struct ShopHome: View {
    @State var selectedCat = CatTabs[0]
    @Namespace var animation
    @State var show = false
    @State var selectedcat: CatModel!
    
    var body: some View {
        
        ZStack {
            VStack(spacing: 0) {
                
                ZStack {
                    HStack(spacing: 15) {
                        
                        Button {
                            
                        }label:{
                            
                            Image(systemName: "line.3.horizontal.decrease")
                                .font(.title)
                                .foregroundColor(.black)
                        }
                        
                        Spacer(minLength: 0)
                        
                        Button {
                            
                        }label:{
                            
                            Image(systemName: "magnifyingglass")
                                .font(.title)
                                .foregroundColor(.black)
                        }
                        
                        ZStack(alignment: Alignment(horizontal: .trailing, vertical: .top)) {
                            
                            Button {
                                
                            }label:{
                                
                                Image(systemName: "cart")
                                    .font(.title)
                                    .foregroundColor(.black)
                            }
                            
                            Circle()
                                .fill(Color.red)
                                .frame(width: 15, height: 15)
                                .offset(x: 5, y: -10)
                        }
                    }
                    
                    Text("Shop")
                        .font(.title)
                        .fontWeight(.heavy)
                        .foregroundColor(.black)
                }
                .padding()
                .padding(.top, UIApplication.shared.windows.first?.safeAreaInsets.top)
                .background(Color.white)
                .shadow(color: Color.black.opacity(0.1), radius: 5, x: 0, y: 5)
                
                ScrollView(.vertical, showsIndicators: false) {
                    
                    VStack {
                        
                        HStack {
                            Text("Cat")
                                .font(.title)
                                .fontWeight(.heavy)
                                .foregroundColor(.black)
                            
                            Spacer(minLength: 0)
                        }
                        .padding(.horizontal)
                        .padding(.top)
                        .padding(.bottom, 10)
                        
                        ScrollView(.horizontal, showsIndicators: false) {
                            
                            HStack(spacing: 15) {
                                
                                ForEach(CatTabs, id: \.self) { tab in
                                    
                                    CatTabButton(title: tab, selectedCat: $selectedCat, animation: animation)
                                }
                            }
                            .padding(.horizontal)
                            .padding(.top, 10)
                        }
                        
                        LazyVGrid(columns: Array(repeating: GridItem(.flexible(), spacing: 15), count: 2), spacing: 15) {
                            
                            ForEach(cats) { cat in
                                
                                CatView(catData: cat, animation: animation)
                                    .onTapGesture {
                                        
                                        withAnimation(.easeIn) {
                                            
                                            selectedcat = cat
                                            show.toggle()
                                        }
                                    }
                            }
                        }
                        .padding()
                        .padding(.top, 10)
                    }
                }
            }
            .background(Color.black.opacity(0.05).ignoresSafeArea(.all, edges: .all))
            
            if selectedcat != nil && show {
                
                CatDetailView(catData: $selectedcat, show: $show, animation: animation)
            }
        }
        .ignoresSafeArea(.all, edges: .top)
    }
}

struct ShopHome_Previews: PreviewProvider {
    static var previews: some View {
        ShopHome()
    }
}
import SwiftUI

struct CatDetailView: View {
    @Binding var catData: CatModel!
    @Binding var show: Bool
    var animation: Namespace.ID
    @State var selectedColor = Color.red
    @State var count = 0
    @State var isSmallDevice = UIScreen.main.bounds.height < 750
    
    var body: some View {
        
        VStack {
            
            HStack {
                
                VStack(alignment: .leading, spacing: 5) {
                    
                    Button {
                        
                        withAnimation(.easeOut) {
                            show.toggle()
                        }
                        
                    }label: {
                        
                        Image(systemName: "chevron.left")
                            .font(.title)
                            .foregroundColor(.white)
                    }
                    
                    Text("Different Cat")
                        .fontWeight(.bold)
                        .foregroundColor(.white)
                        .padding(.top)
                    
                    Text(catData.title)
                        .font(.largeTitle)
                        .fontWeight(.heavy)
                        .foregroundColor(.white)
                }
                
                Spacer(minLength: 0)
                
                Button {
                    
                }label: {
                    
                    Image(systemName: "cart")
                        .font(.title)
                        .foregroundColor(.white)
                }
            }
            .padding()
            .padding(.top, UIApplication.shared.windows.first?.safeAreaInsets.top)
            
            HStack(spacing: 10) {
                
                VStack(alignment: .leading, spacing: 6) {
                    
                    Text("Price")
                        .fontWeight(.bold)
                        .foregroundColor(.white)
                    
                    Text(catData.price)
                        .font(.largeTitle)
                        .fontWeight(.heavy)
                        .foregroundColor(.white)
                }
                
                Image(catData.image)
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .matchedGeometryEffect(id: catData.image, in: animation)
            }
            .padding()
            .padding(.top, 10)
            .zIndex(1)
            
            VStack {
                
                ScrollView(isSmallDevice ? .vertical : .init(), showsIndicators: false) {
                    
                    HStack{
                        
                        VStack(alignment: .leading, spacing: 8) {
                            
                            Text("Color")
                                .fontWeight(.bold)
                                .foregroundColor(.gray)
                            
                            HStack(spacing: 15) {
                                
                                ColorButton(color: Color(catData.image), selectedColor: $selectedColor)
                                
                                ColorButton(color: Color.green, selectedColor: $selectedColor)
                                
                                ColorButton(color: Color.yellow, selectedColor: $selectedColor)
                            }
                        }
                        
                        Spacer(minLength: 0)
                        
                        VStack(alignment: .leading, spacing: 8) {
                            
                            Text("Size")
                                .font(.title)
                                .fontWeight(.semibold)
                                .foregroundColor(.black)
                            
                            Text("12 cm")
                                .fontWeight(.heavy)
                                .foregroundColor(.black)
                        }
                    }
                    .padding(.horizontal)
                    .padding(.top, isSmallDevice ? 0 : -6)
                    
                    Text("I like cat, Mygfgf family..hhh..d.sss.ds.dddafdsdsf.ds.dsfsdgs..dfs..gfdhgfj..hdj.hkdd")
                        .foregroundColor(.gray)
                        .multilineTextAlignment(.leading)
                        .padding()
                    
                    HStack(spacing: 20){
                        
                        Button {
                            if count > 0 {
                                count -= 1
                            }
                        }label: {
                            
                            Image(systemName: "minus")
                                .font(.title2)
                                .foregroundColor(.gray)
                                .frame(width: 35, height: 35)
                                .background(RoundedRectangle(cornerRadius: 10).stroke(Color.gray, lineWidth: 1))
                        }
                        
                        Text("\(count)")
                            .font(.title2)
                        
                        Button {
                            count += 1
                        }label: {
                            
                            Image(systemName: "plus")
                                .font(.title2)
                                .foregroundColor(.gray)
                                .frame(width: 35, height: 35)
                                .background(RoundedRectangle(cornerRadius: 10).stroke(Color.gray, lineWidth: 1))
                        }
                        
                        Spacer()
                        
                        Button {
                            
                        }label: {
                            
                            Image(systemName: "suit.heart.fill")
                                .font(.title2)
                                .foregroundColor(.white)
                                .padding(10)
                                .background(Color.red)
                                .clipShape(Circle())
                        }
                    }
                    .padding(.horizontal)
                    
                    Spacer(minLength: 0)
                    
                    Button {
                        
                    }label: {
                        
                        Text("BUY CAT")
                            .font(.title2)
                            .fontWeight(.bold)
                            .foregroundColor(.white)
                            .padding(.vertical)
                            .frame(width: UIScreen.main.bounds.width - 30)
                            .background(Color(catData.image))
                            .clipShape(Capsule())
                    }
                    .padding(.top)
                    .padding(.bottom, UIApplication.shared.windows.first?.safeAreaInsets.bottom == 0 ? 15 : 0)
                }
            }
            .background(
                Color.white
                    .clipShape(CustomCorner())
                    .padding(.top, isSmallDevice ? -60 : -100)
            )
            .zIndex(0)
            
            
        }
        .background(Color(catData.image).ignoresSafeArea(.all, edges: .top))
        .background(Color.white.ignoresSafeArea(.all, edges: .bottom))
        .onAppear {
            
            // First Color is image or catcolor
            
            selectedColor = Color(catData.image)
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值