• 【SwiftUI模块】0024、SwiftUI创建一个时尚的3D轮播滑块


    SwiftUI模块系列 - 已更新24篇
    SwiftUI项目 - 已更新2个项目
    往期Demo源码下载

    技术:SwiftUI、SwiftUI3.0、3D、轮播滑块、3D轮播滑轮
    运行环境:
    SwiftUI3.0 + Xcode13.4.1 + MacOS12.5 + iPhone Simulator iPhone 13 Pro Max

    概述

    SwiftUI创建一个时尚的3D轮播滑块

    详细

    一、运行效果

    请添加图片描述

    二、项目结构图

    在这里插入图片描述

    三、程序实现 - 过程

    思路:
    1.创建主页 并且使用tabView加载多张图片进行滚动
    2.给每张旋转木马图片设置3D动画处理
    3.统一使用滚动视图偏移的处理器进行处理偏移问题

    1.创建一个项目命名为 MatchedCarousel

    在这里插入图片描述
    在这里插入图片描述

    1.1.引入资源文件和颜色

    颜色
    随机图片8张
    在这里插入图片描述

    2. 创建一个虚拟文件New Group 命名为 View

    在这里插入图片描述
    在这里插入图片描述

    3. 创建一个文件New File 选择SwiftUI View类型 命名为Home

    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    4. 创建一个文件New File 选择SwiftUI View类型 命名为CarouselBodyView

    主要是: 用来加载TabView的每一张图片的3d转场动画的处理

    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    5. 创建一个文件New File 选择SwiftUI View类型 命名为ScrollViewOffsetModifier

    在这里插入图片描述
    在这里插入图片描述

    Code

    ContentView - 主窗口

    主要是展示主窗口Home

    //
    //  ContentView.swift
    //  Shared
    //
    //  Created by 李宇鸿 on 2022/9/5.
    //
    
    import SwiftUI
    
    struct ContentView: View {
        var body: some View {
           Home()
        }
    }
    
    struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            ContentView()
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    Home - 主页

    思路

    1. 主要是用来展示tabView的多张图片
    //
    //  Home.swift
    //  MatchedCarousel (iOS)
    //
    //  Created by 李宇鸿 on 2022/9/5.
    //
    
    import SwiftUI
    
    struct Home: View {
        
        
        // 背景将是当前标签图像…
        @State var currentTab = "p1"
        var body: some View {
            ZStack{
                // 获取屏幕大小的几何读取器…
                GeometryReader{proxy in
                    let size = proxy.size
                    
                    Image(currentTab)
                        .resizable()
                        .aspectRatio(contentMode: .fill)
                        .frame(width: size.width, height: size.height)
                        .cornerRadius(1)
                    
                }
                .ignoresSafeArea()
                // 材料的效果……
                .overlay(.ultraThinMaterial)
                // 暗黑模式
                .colorScheme(.dark)
    
                // 旋转木马列表
                TabView(selection: $currentTab) {
                    ForEach(1...7,id:\.self){index  in
                        
                        // 旋转木马视图
                        CarouselBodyView(index:index)
                    }
                }
                
                //页面标签风格……
                .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
                
                
            }
    
        }
    }
    
    struct Home_Previews: PreviewProvider {
        static var previews: some View {
            ContentView()
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    CarouselBodyView - 每一张3D转场动画的图片
    //
    //  CarouselBodyView.swift
    //  MatchedCarousel (iOS)
    //
    //  Created by 李宇鸿 on 2022/9/5.
    //
    
    import SwiftUI
    
    struct CarouselBodyView: View {
        var index : Int
        // Offset
        @State var offset : CGFloat = 0
        var body: some View {
           
            GeometryReader{proxy in
                let size = proxy.size
                
                ZStack{
                    Image("p\(index)")
                        .resizable()
                        .aspectRatio(contentMode: .fill)
                        .frame(width: size.width - 8, height: size.height / 1.2)
                        .cornerRadius(12)
                    
                    VStack{
                        VStack(alignment: .leading, spacing: 10) {
                            Text("Human Integration Supervisor")
                                .font(.title2.bold())
                            //letter spacing...
                                .kerning(1.5)
                            
                            Text("The world's largest collection of animal facts, pictures and more!")
                                .kerning(1.2)
                                .foregroundStyle(.secondary)
    
                        }
                        .foregroundStyle(.white)
                        .padding(.top)
                        Spacer(minLength: 0)
                        
                        
                        VStack(alignment:.leading, spacing:30){
                            HStack(spacing:15){
                                Image("justine")
                                    .resizable()
                                    .aspectRatio(contentMode: .fill)
                                    .frame(width: 55, height: 55)
                                    .clipShape(Circle())
                                
                                VStack(alignment: .leading, spacing: 6) {
                                    
                                    Text("iJustine")
                                        .font(.title2.bold())
                                    
                                    Text("Apple Sheep")
                                        .foregroundStyle(.secondary)
                                }
                                .foregroundStyle(.black)
                                
                                
                                
                            }
                        
                            
                            HStack{
                                VStack{
                                    Text("1303")
                                        .font(.title2.bold())
                                    Text("Posts")
                                        .foregroundStyle(.secondary)
                                }
                                .frame(maxWidth:.infinity)
                                
                                
                                VStack{
                                    Text("3103")
                                        .font(.title2.bold())
                                    Text("Followers")
                                        .foregroundStyle(.secondary)
                                }
                                .frame(maxWidth:.infinity)
                                
                                
                                VStack{
                                    Text("1503")
                                        .font(.title2.bold())
                                    Text("Following")
                                        .foregroundStyle(.secondary)
                                }
                                .frame(maxWidth:.infinity)
                                
                                
                            }
                            .foregroundStyle(.black)
                            
                        }
                        .padding(20)
                        .padding(.horizontal,10)
                        .background(.white,in:RoundedRectangle(cornerRadius: 4))
                    }
                    .padding(20)
    
                }
                .frame(width: size.width - 8, height: size.height / 1.2)
                .frame(width: size.width, height: size.height)
                
            }
            // 设置tag
            .tag("p\(index)")
             //旋转……
            //基于偏移量的锚
            .rotation3DEffect(.init(degrees: getProgress() * 90), axis: (x: 0, y: 1, z: 0),anchor: offset > 0 ? .leading : .trailing,anchorZ: 0,perspective: 0.6)
            
    
            //自定义3D旋转…
    		//因为我们需要从0开始,所以我们得到前导偏移量…
            .modifier(ScrollViewOffsetModifier(anchorPoint: .leading, offset: $offset))
    //        .overlay(Text("\(offset)").foregroundColor(.white))
            
            
            
        }
        
        
        // 获取进度
        func getProgress()-> CGFloat{
            let progress = -offset / UIScreen.main.bounds.width
            return progress
        }
    }
    
    struct CarouselBodyView_Previews: PreviewProvider {
        static var previews: some View {
            ContentView()
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    ScrollViewOffsetModifier - 主要是监听ScrollView的滚动

    用来监听ScrollView的滚动 偏移量的改变

    //
    //  ScrollViewOffsetModifier.swift
    //  MatchedCarousel (iOS)
    //
    //  Created by 李宇鸿 on 2022/9/5.
    //
    
    import SwiftUI
    
    struct ScrollViewOffsetModifier: ViewModifier {
      
        var anchorPoint : Anchor = .top
        @Binding var offset : CGFloat
        
        func body(content: Content)-> some View{
            content
                .overlay(
                    GeometryReader{proxy -> Color in
                        let frame = proxy.frame(in:.global)
                        
                        DispatchQueue.main.async {
                            
                            switch anchorPoint {
                            case .top:
                                offset = frame.minY
                            case .bottom:
                                offset = frame.maxY
                            case .leading:
                                offset = frame.minX
                            case .trailing:
                                offset = frame.maxX
                            }
                            
                        }
                        
                        return Color.clear
                        
                    }
                )
        }
        
    }
    
    
    //自定义修改ScrollView或标签视图…
    //枚举自定义锚…
    
    enum Anchor{
        case top
        case bottom
        case leading
        case trailing
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
  • 相关阅读:
    国际阿里云服务器买哪种好用点?
    Nginx + tomcat 搭建
    xss漏洞简单案例
    LeetCode【128】最长连续序列
    CSS 常用样式 显示模式
    DDD系列 实战一 应用设计案例 (golang)
    windows下使用php-ffmpeg获取视频第一帧的图片
    Java:String、StringBuffer和StringBuilder的区别学习
    力扣刷题记录53.1-----700. 二叉搜索树中的搜索
    HTML5使用html2canvas转化为图片,然后再转为base64.
  • 原文地址:https://blog.csdn.net/qq_42816425/article/details/126696686