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

技术:SwiftUI、SwiftUI3.0、3D转换、视图切换、过渡动画
运行环境:
SwiftUI3.0 + Xcode13.4.1 + MacOS12.5 + iPhone Simulator iPhone 13 Pro Max


SwiftUI搭建一个视图之间的立方体3D自定义转换过渡动画

  • 概述
  • 详细
  • 一、运行效果
  • 二、项目结构图
  • 三、程序实现 - 过程
  • 1.创建一个项目命名为 `CustomTransition`
  • 1.1.引入资源文件和颜色
  • 2. 创建一个虚拟文件`New Group` 命名为 `View`
  • 3. 创建一个文件`New File` 选择`SwiftUI View`类型 命名为`Home`
  • 4. 创建一个文件`New File` 选择`SwiftUI View`类型 命名为`CubicTransition`
  • Code
  • ContentView - 主窗口
  • Home - 主页
  • CubicTransition - `过渡动画`


概述

使用SwiftUI搭建一个视图之间的立方体3D自定义转换过渡动画

详细

一、运行效果

swiftUI 发送GET请求 swiftui form_iOS

二、项目结构图

swiftUI 发送GET请求 swiftui form_swiftUI 发送GET请求_02

三、程序实现 - 过程

思路:
1.搭建主页部分
2.创建一个过渡动画的类、记录当前详情页和上一个页 、以及是否显示主页的属性
3.过渡动画类 处理当前页 和 下一个页面的偏移的逻辑处理 。比如当前页进行当前页跳转。下一个就进行3d动画过渡偏移整个屏幕

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

swiftUI 发送GET请求 swiftui form_swiftui_03


swiftUI 发送GET请求 swiftui form_iOS_04

1.1.引入资源文件和颜色

背景图片2张

swiftUI 发送GET请求 swiftui form_iOS_05

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

swiftUI 发送GET请求 swiftui form_视图切换_06


swiftUI 发送GET请求 swiftui form_swiftUI 发送GET请求_07

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

swiftUI 发送GET请求 swiftui form_3D转换_08


swiftUI 发送GET请求 swiftui form_swiftui_09

swiftUI 发送GET请求 swiftui form_iOS_10

swiftUI 发送GET请求 swiftui form_swiftUI 发送GET请求_11

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

swiftUI 发送GET请求 swiftui form_3D转换_08


swiftUI 发送GET请求 swiftui form_3D转换_13

swiftUI 发送GET请求 swiftui form_3D转换_14

swiftUI 发送GET请求 swiftui form_swiftUI 发送GET请求_15

Code

ContentView - 主窗口

主要是展示主窗口Home

//
//  ContentView.swift
//  Shared
//
//  Created by 李宇鸿 on 2022/9/4.
//

import SwiftUI

struct ContentView: View {
    var body: some View {
        Home()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
Home - 主页

思路:
1.搭建主页部分
2.创建一个过渡动画的类、记录当前详情页和上一个页 、以及是否显示主页的属性
3.过渡动画类 处理当前页 和 下一个页面的偏移的逻辑处理 。比如当前页进行当前页跳转。下一个就进行3d动画过渡偏移整个屏幕

//
//  Home.swift
//  CustomTransition (iOS)
//
//  Created by 李宇鸿 on 2022/9/4.
//

import SwiftUI

struct Home: View {
    @State var show : Bool = false
    var body: some View {
        GeometryReader{proxy in
            let size = proxy.size
            
            CubicTransition(show:$show) {
                
                ZStack{
                    Image("Pic1")
                        .resizable()
                        .aspectRatio(contentMode: .fill)
                        .frame(width: size.width, height: size.height)
                        .clipped()
                    
                    Button{
                        // 使用点击屏幕测试来回切换 引发bug的处理
//                        show.toggle()
                    }label: {
                        Text("Navigate")
                            .font(.title3)
                            .foregroundColor(.white)
                            .padding()
                            .background(.ultraThinMaterial)
                            .cornerRadius(10)
                            .environment(\.colorScheme, .dark)
                    }
                    .offset(y: 150)

                }
                
            } detail: {
                Image("Pic2")
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .frame(width: size.width, height: size.height)
                    .clipped()

            }

        }
        .ignoresSafeArea()
        .overlay(alignment: .top) {
            HStack(spacing:12){
                
                if show {
                    Button  {
                        show.toggle()
                    } label: {
                        Image(systemName: "arrow.left")
                            .font(.title2)
                            .foregroundColor(.white)
                    }

                }
                
                Text(show ? "Back" : "Custom transition")
                    .font(.title.bold())
                    .foregroundColor(.white)
            }
            .padding()
            .padding(.top,4)
            .frame(maxWidth:.infinity,alignment: .leading)
            .background(.ultraThinMaterial)
            .environment(\.colorScheme, .dark)
        }
        .onTapGesture{
            show.toggle()
        }
    }
}

struct Home_Previews: PreviewProvider {
    static var previews: some View {
        Home()
    }
}
CubicTransition - 过渡动画

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

//  CubicTransition.swift
//  CustomTransition (iOS)
//
//  Created by 李宇鸿 on 2022/9/4.
//

import SwiftUI

struct CubicTransition<Content: View,Detail:View>: View {
    
    var cotnent: Content
    var detail: Detail
    
    // 显示视图
    @Binding var show : Bool
    
    init(show:Binding<Bool>,
         @ViewBuilder content: @escaping ()-> Content,
         @ViewBuilder detail: @escaping()->Detail) {
        self.detail = detail()
        self.cotnent = content()
        self._show = show
    }
    
    
    
    // 动画属性
    @State var animateView : Bool = false
    @State var showView : Bool = false
    
    // 避免用户一直来回切换引起的bug - 没有将当前视图移除问题
    @State var task : DispatchWorkItem?

    var body: some View {
        
        GeometryReader{proxy in
            let size = proxy.size
            HStack(spacing:0){
                cotnent
                    .frame(width: size.width, height: size.height)
                // 当detail View被push时旋转当前视图
                    .rotation3DEffect(.init(degrees: animateView ? -85 : 0), axis: (x: 0, y: 1, z: 0),anchor: .trailing,anchorZ: 0,perspective: 1)
                
				// 显示详细信息视图
                ZStack{
                    if showView {
                        detail.frame(width: size.width, height: size.height)
                            .transition(.move(edge: .trailing))
                            .onDisappear{
                                print("Colosed")
                            }
                    }
                }
                .rotation3DEffect(.init(degrees: animateView ? 0 : 85), axis: (x: 0, y: 1, z: 0),anchor: .leading,anchorZ: 0,perspective: 1)

            
            }
            // 应用抵消
            .offset(x:animateView ?  -size.width : 0)
        }
        .onChange(of: show) { newValue in
            task?.cancel()
            
            
            
            // 在动画星星前显示视图
            if show {
                showView = true
            }
            // 视图未被删除,因此它将产生内存问题
            else {
                //当动画完成时关闭视图
                //在0.35秒之后
                
                // 避免用户一直来回切换引起的bug - 没有将当前视图移除问题
                // 为了避免这个问题
                
                task = .init{
                    showView = false

                }
                
                if let task = task {
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.35,execute: task)
                }
                
              
            }

            
            //为什么使用单独的变量而不是显示
            //因为一旦它设置为false,它就会删除
            //这样动画将不会完成
            
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
                withAnimation(.easeInOut(duration: 0.35)){
                    animateView.toggle()
                }
            }
            
            
        }
    }
}

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