SwiftUI框架详细解析 (三) —— 基于SwiftUI的闪屏页的创建(二)

版本记录

版本号 时间
V1.0 2019.09.16 星期一

前言

今天翻阅苹果的API文档,发现多了一个框架SwiftUI,这里我们就一起来看一下这个框架。感兴趣的看下面几篇文章。
1. SwiftUI框架详细解析 (一) —— 基本概览(一)
2. SwiftUI框架详细解析 (二) —— 基于SwiftUI的闪屏页的创建(一)

源码

1. Swift

首先看下工程组织结构

下面看一下代码

1. AppDelegate.swift
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
  // MARK: - UISceneSession Lifecycle
  
  func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
    // Called when a new scene session is being created.
    return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
  }
}
2. SceneDelegate.swift
import UIKit
import SwiftUI

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
  var window: UIWindow?
  
  func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    // Use a UIHostingController as window root view controller
    if let windowScene = scene as? UIWindowScene {
      let window = UIWindow(windowScene: windowScene)
      window.rootViewController = UIHostingController(rootView: ContentView())
      self.window = window
      window.makeKeyAndVisible()
    }
  }
}
3. ContentView.swift
import SwiftUI
import MapKit

struct ContentView: View {
  @State var showSplash = true
  
  var body: some View {
    ZStack{
      MapView(coordinate: CLLocationCoordinate2DMake(37.331820, -122.03118))
        .edgesIgnoringSafeArea(.all)
      SplashScreen()
        .opacity(showSplash ? 1 : 0)
        .onAppear {
          DispatchQueue.main.asyncAfter(deadline: .now() + 10) {
            SplashScreen.shouldAnimate = false
            withAnimation() {
              self.showSplash = false
            }
          }
      }
    }
  }
}

#if DEBUG
struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    ContentView()
  }
}
#endif
4. SplashScreen.swift
import SwiftUI

struct SplashScreen: View {
  static var shouldAnimate = true
  let fuberBlue = Color("Fuber blue")
  let uLineWidth: CGFloat = 5
  let uZoomFactor: CGFloat = 1.4
  let lineWidth:  CGFloat = 4
  let lineHeight: CGFloat = 28
  let uSquareLength: CGFloat = 12
  
  @State var percent = 0.0
  @State var uScale: CGFloat = 1
  @State var squareColor = Color.white
  @State var squareScale: CGFloat = 1
  @State var lineScale: CGFloat = 1
  @State var textAlpha = 0.0
  @State var textScale: CGFloat = 1
  @State var coverCircleScale: CGFloat = 1
  @State var coverCircleAlpha = 0.0
  
  var body: some View {
    ZStack {
      Image("Chimes")
        .resizable(resizingMode: .tile)
        .opacity(textAlpha)
        .scaleEffect(textScale)
      
      Circle()
        .fill(fuberBlue)
        .frame(width: 1, height: 1,
               alignment: .center)
        .scaleEffect(coverCircleScale)
        .opacity(coverCircleAlpha)
      
      Text("F           BER")
        .font(.largeTitle)
        .foregroundColor(.white)
        .opacity(textAlpha)
        .offset(x: 20, y: 0)
        .scaleEffect(textScale)
      
      FuberU(percent: percent)
        .stroke(Color.white, lineWidth: uLineWidth)
        .rotationEffect(.degrees(-90))
        .aspectRatio(1, contentMode: .fit)
        .padding(20)
        .onAppear() {
          self.handleAnimations()
      }
      .scaleEffect(uScale * uZoomFactor)
      .frame(width: 45, height: 45,
             alignment: .center)
      
      Rectangle()
        .fill(squareColor)
        .scaleEffect(squareScale * uZoomFactor)
        .frame(width: uSquareLength, height: uSquareLength,
               alignment: .center)
        .onAppear() {
          self.squareColor = self.fuberBlue
      }
      
      Rectangle()
        .fill(fuberBlue)
        .scaleEffect(lineScale, anchor: .bottom)
        .frame(width: lineWidth, height: lineHeight,
               alignment: .center)
        .offset(x: 0, y: -22)
      
      Spacer()
    }
    .background(fuberBlue)
    .edgesIgnoringSafeArea(.all)
  }
}

extension SplashScreen {
  var uAnimationDuration: Double { return 1.0 }
  var uAnimationDelay: Double { return  0.2 }
  var uExitAnimationDuration: Double { return 0.3 }
  var finalAnimationDuration: Double { return 0.4 }
  var minAnimationInterval: Double { return 0.1 }
  var fadeAnimationDuration: Double { return 0.4 }
  
  func handleAnimations() {
    runAnimationPart1()
    runAnimationPart2()
    runAnimationPart3()
    if SplashScreen.shouldAnimate {
      restartAnimation()
    }
  }
  
  func runAnimationPart1() {
    withAnimation(.easeIn(duration: uAnimationDuration)) {
      percent = 1
      uScale = 5
      lineScale = 1
    }
    
    withAnimation(Animation.easeIn(duration: uAnimationDuration).delay(0.5)) {
      textAlpha = 1.0
    }
    
    let deadline: DispatchTime = .now() + uAnimationDuration + uAnimationDelay
    DispatchQueue.main.asyncAfter(deadline: deadline) {
      withAnimation(.easeOut(duration: self.uExitAnimationDuration)) {
        self.uScale = 0
        self.lineScale = 0
      }
      withAnimation(.easeOut(duration: self.minAnimationInterval)) {
        self.squareScale = 0
      }
      
      withAnimation(Animation.spring()) {
        self.textScale = self.uZoomFactor
      }
    }
  }
  
  func runAnimationPart2() {
    let deadline: DispatchTime = .now() + uAnimationDuration + uAnimationDelay + minAnimationInterval
    DispatchQueue.main.asyncAfter(deadline: deadline) {
      self.squareColor = Color.white
      self.squareScale = 1
      withAnimation(.easeOut(duration: self.fadeAnimationDuration)) {
        self.coverCircleAlpha = 1
        self.coverCircleScale = 1000
      }
    }
  }
  
  func runAnimationPart3() {
    DispatchQueue.main.asyncAfter(deadline: .now() + 2*uAnimationDuration) {
      withAnimation(.easeIn(duration: self.finalAnimationDuration)) {
        self.textAlpha = 0
        self.squareColor = self.fuberBlue
      }
    }
  }
  
  func restartAnimation() {
    let deadline: DispatchTime = .now() + 2*uAnimationDuration + finalAnimationDuration
    DispatchQueue.main.asyncAfter(deadline: deadline) {
      self.percent = 0
      self.textScale = 1
      self.coverCircleAlpha = 0
      self.coverCircleScale = 1
      self.handleAnimations()
    }
  }
}

struct FuberU: Shape {
  var percent: Double
  
  func path(in rect: CGRect) -> Path {
    let end = percent * 360
    var p = Path()
    
    p.addArc(center: CGPoint(x: rect.size.width/2, y: rect.size.width/2),
             radius: rect.size.width/2,
             startAngle: Angle(degrees: 0),
             endAngle: Angle(degrees: end),
             clockwise: false)
    
    return p
  }
  
  var animatableData: Double {
    get { return percent }
    set { percent = newValue }
  }
}

#if DEBUG
struct SplashScreen_Previews : PreviewProvider {
  static var previews: some View {
    SplashScreen()
  }
}
#endif
5. MapView.swift
import SwiftUI
import MapKit

struct MapView: UIViewRepresentable {
  var coordinate: CLLocationCoordinate2D
  
  func makeUIView(context: Context) -> MKMapView {
    MKMapView(frame: .zero)
  }
  
  func updateUIView(_ view: MKMapView, context: Context) {
    let span = MKCoordinateSpan(latitudeDelta: 2.0, longitudeDelta: 2.0)
    let region = MKCoordinateRegion(center: coordinate, span: span)
    view.setRegion(region, animated: true)
  }
}

#if DEBUG
struct MapView_Previews : PreviewProvider {
  static var previews: some View {
    MapView(coordinate: CLLocationCoordinate2DMake(0,0))
  }
}
#endif

后记

本篇主要讲述了基于SwiftUI的闪屏页的创建,感兴趣的给个赞或者关注~~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,326评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,228评论 1 304
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,979评论 0 252
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,489评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,894评论 3 294
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,900评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,075评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,803评论 0 205
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,565评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,778评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,255评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,582评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,254评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,151评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,952评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,035评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,839评论 2 277

推荐阅读更多精彩内容