【SwiftUI模块】0008、SwiftUI-自定义启动闪屏动画-App启动闪屏曲线路径动画

SwiftUI小功能模块系列
0001、SwiftUI自定义Tabbar动画效果
0002、SwiftUI自定义3D动画导航抽屉效果
0003、SwiftUI搭建瀑布流-交错网格-效果
0004、SwiftUI-<探探App>喜欢手势卡片
0005、SwiftUI-粘性动画指示器引导页
0006、SwiftUI自定义引导页动画
0007、SwiftUI聚光灯介绍说明
0008、SwiftUI-自定义启动闪屏动画-App启动闪屏曲线路径动画

技术:SwiftUI、SwiftUI3.0、动画闪屏、启动动画闪屏、启动闪屏曲线路径动画、动画灵感 - 来自德国的freYfahrt打车软件
运行环境:
SwiftUI3.0 + Xcode13.4.1 + MacOS12.5 + iPhone Simulator iPhone 13 Pro Max

概述

使用SwiftUI做一个App启动闪屏logo定制曲线路径的案例

详细

一、运行效果

请添加图片描述

二、项目结构图

在这里插入图片描述

三、程序实现 - 过程

思路:
1.创建闪屏动画页面
2.画图 画出 J 、| 、和J的倒放2个小圆点 然后控制动画
3.创建 主页 导航 + 滚动视图 + N个图片
4.处理闪屏动画结束 展示主页逻辑

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

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

1.1.引入资源文件和颜色

颜色
SplashColor #DD8482
随机图片5张

在这里插入图片描述

扫描二维码关注公众号,回复: 14509022 查看本文章

1.2 设置启动闪屏的背景颜色跟闪屏背景颜色同步

在这里插入图片描述

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

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

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

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

在这里插入图片描述

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

主要是: 展示 闪屏过后的首页

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

在这里插入图片描述

Code

ContentView - 主窗口

主要是展示主窗口Home和闪屏页面
一开始是闪屏页面 。闪屏动画执行完毕 就会偏移y为整个屏幕的高度。
所以首页需要判断是否动画结束完成 完成就进行一个偏移

//
//  ContentView.swift
//  Shared
//
//  Created by 李宇鸿 on 2022/8/19.
//

import SwiftUI

struct ContentView: View {
    
    
    // 当动画完成时做动作…
    @State var endAnimation : Bool = false
    var body: some View {
    
    
        
        ZStack {
    
    
            
            Home()
            // 一开始将首页y设置为0 动画过渡完毕 就偏移到整个屏幕的高度
                .offset(y:endAnimation ? 0 :  getRect().height)
            SplashScreen(endAnimation:$endAnimation)
        }
    }
}

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

Home - 主页

思路

  1. 主要就是展示一个导航栏 + 滚动视图 + 多张图片
//
//  Home.swift
//  SplashsAnimation (iOS)
//
//  Created by 李宇鸿 on 2022/8/19.
//

import SwiftUI

struct Home: View {
    
    
    var body: some View {
    
    
        
        NavigationView{
    
    
            
            ScrollView(.vertical,showsIndicators: false) {
    
    
                
                VStack(spacing:20){
    
    
                    
                    ForEach(1...5,id:\.self){
    
    index in
                        
                        Image("Pic\(index)")
                            .resizable()
                            .aspectRatio(contentMode: .fit)
                            .frame(width: getRect().width - 30, height: 220)
                            .cornerRadius(15)
                    }
                }
                .padding(15)
            }
            .navigationTitle("Trending Posts")

        }
    }
}

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

SplashScreen - 闪屏动画页面

做法思路

  1. 画出几个图形
    J 、| 、和J的倒放2个小圆点
    在这里插入图片描述
  2. 通过逻辑去控制每一个的动画 - 注意其中 J 、| 、和J的倒放是一个动画组
  3. 控制动画结束之后 展示首页
//
//  SplashScreen.swift
//  SplashsAnimation (iOS)
//
//  Created by 李宇鸿 on 2022/8/19.
//

import SwiftUI

struct SplashScreen: View {
    
    
    
    
    
    // 动画属性……
    @State var startAnimation : Bool = false
    
    
    @State var circleAnimation1 : Bool = false
    @State var circleAnimation2 : Bool = false
    
    // 结束的动画
    @Binding var endAnimation : Bool

    var body: some View {
    
    
        ZStack{
    
    
            Color("SplashColor")
            Group{
    
    
                
                // 自定义形状与动画…
                SplashShape()
                // 修剪
                    .trim(from: 0, to: startAnimation ? 1 : 0)
                // 描边得到轮廓
                    .stroke(Color.white,style: StrokeStyle(lineWidth: 30, lineCap: .round, lineJoin: .round))
                
                
                // 两个圆……
                Circle()
                    .fill(.white)
                    .frame(width: 35, height: 35)
                    .scaleEffect(circleAnimation1 ? 1 : 0)
                    .offset(x:-80, y: 22)
                
                
                Circle()
                    .fill(.white)
                    .frame(width: 35, height: 35)
                    .scaleEffect(circleAnimation2 ? 1 : 0)
                    .offset(x:80, y: -22)
            }
            // 默认尺寸
            .frame(width:220,height:130)
            // 如果是动画已经结束 就缩放到0.15倍
            .scaleEffect(endAnimation ? 0.15 :  0.9)
            .rotationEffect(.init(degrees: endAnimation ? 85: 0))
            
            // 底部文案
            VStack{
    
    
                Text("Powered by")
                    .font(.callout)
                    .fontWeight(.semibold)
                
                Text("宇夜iOS")
                    .font(.title2)
                    .fontWeight(.semibold)

            }
            .frame(maxHeight:.infinity,alignment: .bottom)
            .foregroundColor(Color.white.opacity(0.8))
            .padding(.bottom,getSafeArea().bottom == 0 ? 15 : getSafeArea().bottom)
            .opacity(startAnimation ? 1 : 0)
            .opacity(endAnimation ? 0 : 1)
        }
        // 移动视图…
        .offset(y:endAnimation ? (-getRect().height * 1.5) : 0)
        .ignoresSafeArea()
        .onAppear {
    
    
            // 推迟开始……
            withAnimation(.spring().delay(0.15)){
    
    
                // 第一圈……
                circleAnimation1.toggle()
            }
            
            // 下一个形状……
            withAnimation(.interactiveSpring(response: 0.7, dampingFraction: 1.05, blendDuration: 1.05).delay(0.3)){
    
    
                startAnimation.toggle()
            }
            
            // 最后一个圆
            withAnimation(.spring().delay(0.7)){
    
    
                circleAnimation2.toggle()

            }
            
            
            // 动画结束
            withAnimation(.interactiveSpring(response: 0.7, dampingFraction: 1.05, blendDuration: 1.05).delay(1.2)){
    
    
                endAnimation.toggle()
            }
            
        }
    }
}

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


// 扩展视图以获得屏幕框架…
extension View{
    
    
    func getRect()->CGRect{
    
    
        return UIScreen.main.bounds
    }
    
    // 安全的地方
    func getSafeArea()->UIEdgeInsets{
    
    
        guard let screen = UIApplication.shared.connectedScenes.first as? UIWindowScene else{
    
    
            return .zero
        }
        guard let safeArea = screen.windows.first?.safeAreaInsets else{
    
    
            return .zero
        }
        
        return safeArea
    }
}

struct SplashShape: Shape {
    
    
    // 画出3个路径 J | J的反转
    func path(in rect: CGRect) -> Path {
    
    
        return Path{
    
     path in
            let mid = rect.width / 2
            let height = rect.height
            
            // 80 = 40:弧半径…
            path.move(to: CGPoint(x: mid - 80, y:height))
            path.addArc(center: CGPoint(x: mid - 40 , y: height), radius: 40, startAngle: .init(degrees: 180), endAngle: .zero, clockwise: true)
            
            // 直线……
            path.move(to: CGPoint(x: mid, y: height))
            path.addLine(to: CGPoint(x: mid, y: 0))
            
            // 另一个弧…
            path.addArc(center: CGPoint(x: mid + 40 , y: 0), radius: 40, startAngle: .init(degrees: -180), endAngle: .zero, clockwise: false)

        }
    }
}

demo源码

如需看源码,请点击下载!

猜你喜欢

转载自blog.csdn.net/qq_42816425/article/details/126430862