前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SwiftUI案例:3D旋转图片播放器

SwiftUI案例:3D旋转图片播放器

作者头像
DioxideCN
发布2022-08-05 19:23:35
2.3K0
发布2022-08-05 19:23:35
举报

SwiftUI案例:3D旋转图片播放器

效果

3D效果
3D效果

目标

  • 实现多张图片的3D切换查看功能

外观配置

任选 7 张任意尺寸的图片按 p1p7 进行命名并拖拽进 Assets.xcassets 文件中(如图所示)

配置图片
配置图片

创建View视图

在工作区的项目文件夹下创建名为 ViewGroup 并在其中依次创建 Home.swift CarouseBodyView.swift ScrollViewOffsetModifier.swift 视图文件,其功能如下:

  1. Home.swift: 主视图,用来控制文字布局与图片布局;
  2. CarouseBodyView.swift: 控件视图,用来具体实现文字部分与图片部分;
  3. ScrollViewOffsetModifier.swift: 滚动偏量视图,用来设置3D滚动效果;

视图的实现

主视图 Home.swift

大致定义整个屏幕视图的布局与容器接口。

代码语言:javascript
复制
import SwiftUI

struct Home: View {
	//定义当前的图片
    @State var currentTab = "p1"
    var body: some View {
        //ZStack视图容器
        ZStack {
            GeometryReader {
            	//背景阅读器
                proxy in
                let size = proxy.size
                //图片样式
                Image(currentTab)
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .frame(width: size.width, height: size.height)
                    .cornerRadius(1)
            }
            //约束ZStack容器样式
            .ignoresSafeArea()
            .overlay(.ultraThinMaterial)
            .colorScheme(.dark)
            //调用CarouseBodyView控件将图片信息返回给currentTab变量
            TabView(selection: $currentTab) {
                ForEach(1...7, id: \.self) { index in
                    CarouseBodyView(index: index)
                }
            }
            .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
        }
    }
}

struct Home_Previews: PreviewProvider {
    static var previews: some View {
        Home()
    }
}

控件视图 CarouseBodyView.swift

通过视图容器的嵌套布局,实现 Home.swift 中组件的文本与图片的具体内容。

代码语言:javascript
复制
import SwiftUI

struct CarouseBodyView: View {
	//整型index标注图片序号
    var index: Int
    //定义浮点型offset偏量大小
    @State var offset:CGFloat = 0
    var body: some View {
        GeometryReader {proxy in
            let size = proxy.size
            ZStack {
            	//通过index来显示指定图片
                Image("p\(index)")
                	//设置图片样式
                    .resizable()
                    .aspectRatio( contentMode: .fill)
                    .frame(width: size.width - 8, height: size.height / 1.2, alignment: .center)
                    .cornerRadius(12) //圆角
                //嵌套VStack(垂直排列子元素的视图)容器
                VStack(spacing: 25) {
                	//嵌套VStack容器
                    VStack(alignment: .leading, spacing: 10) {
                        Text("标题")
                            .font(.title2.bold())
                            .kerning(1.5)
                        Text("副标题")
                            .foregroundStyle(.primary)
                    }
                    .foregroundStyle(.white)
                    .padding(.top)
                    Spacer()
                    VStack (alignment:.leading){
                    	//嵌套HStack容器
                        HStack( spacing: 25) {
                            Image("justine")
                                .resizable()
                                .aspectRatio(contentMode: .fill)
                                .frame(width: 55, height: 55)
                                .clipShape(Circle())
                            VStack(alignment: .leading, spacing: 6) {
                                Text("Dioxide.CN")
                                    .font(.title2.bold())
                                Text("个人开发者")
                                    .foregroundStyle(.secondary)
                            }
                            .foregroundStyle(.black)
                        }
                        //嵌套HStack容器
                        HStack {
                            VStack {
                                Text("2022")
                                    .font(.title2.bold())
                                Text("文章")
                                    .foregroundStyle(.secondary)
                            }
                            .frame(maxWidth: .infinity)
                            VStack {
                                Text("1000")
                                    .font(.title2.bold())
                                Text("粉丝")
                                    .foregroundStyle(.secondary)
                            }
                            .frame(maxWidth: .infinity)
                            //嵌套VStack容器
                            VStack {
                                Text("50")
                                    .font(.title2.bold())
                                Text("关注者")
                                    .foregroundStyle(.secondary)
                            }
                            .frame(maxWidth: .infinity)
                        }
                        .padding(.top)
                    }
                    .padding(20)
                    .padding(.horizontal)
                    .background(.white)
                    .cornerRadius(12)
                }
                .padding(20)
            }
            .frame(width: size.width - 8, height: size.height / 1.2)
            .frame(width: size.width, height: size.height)
        }
        .tag("p\(index)")
        
        //调用getProgress()函数设置整体容器偏量
        .rotation3DEffect(
        	.init(degrees: getProgress() * 90), //旋转度数
            axis:(x:0, y: 1, z: 0), 
            anchor: offset > 0 ?.leading : .trailing, //锚点
            anchorZ: 0, 
            perspective: 0.5
        )
        
        //调用ScrollViewOffsetModifier控件定义3D旋转动画
        .modifier(
        	ScrollViewOffsetModifier(
            	anchorPoint: .leading, 
                offset: $offset
            )
        )
    }
    
    func getProgress()->CGFloat {
    	//progress = (-)偏移 ÷ 弹性screen宽度
        let progress = -offset / UIScreen.main.bounds.width
        return progress
    }
}

struct CarouseBodyView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

滚动偏量视图 ScrollViewOffsetModifier.swift

这类似于 css 中的 transform: rotateX() transform: rotateY() 属性,通过屏幕反馈的滑动位置来控制每个图片组件的 X Y 轴偏量。

代码语言:javascript
复制
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和tab视图定义修饰器
//枚举锚点位置
enum Anchor {
    case top
    case bottom
    case leading
    case trailing
}

源码

3d-carousel-slider.zip

来源:百度网盘 | 提取码:up0f

3d-carousel-slider.zip

来源:蓝奏云网盘 | 提取码:1z5b

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • SwiftUI案例:3D旋转图片播放器
    • 效果
      • 目标
        • 外观配置
          • 创建View视图
            • 视图的实现
              • 主视图 Home.swift
              • 控件视图 CarouseBodyView.swift
              • 滚动偏量视图 ScrollViewOffsetModifier.swift
            • 源码
            相关产品与服务
            容器服务
            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档