iOS CAEmitterLayer 實現粒子發射動畫效果

来源:http://www.cnblogs.com/silence-cnblogs/archive/2017/06/09/6971533.html
-Advertisement-
Play Games

iOS CAEmitterLayer 實現粒子發射動畫效果 效果圖 代碼已上傳 GitHub:https://github.com/Silence GitHub/CoreAnimationDemo 動畫效果用 CAEmitterLayer 實現。CAEmitterLayer 顯示粒子發射動畫,具體的 ...


iOS CAEmitterLayer 實現粒子發射動畫效果

效果圖

代碼已上傳 GitHub:https://github.com/Silence-GitHub/CoreAnimationDemo

動畫效果用 CAEmitterLayer 實現。CAEmitterLayer 顯示粒子發射動畫,具體的粒子由 CAEmitterCell 封裝。代碼示例是展示 CAEmitterLayer 如何使用。為了方便,直接在控制器(UIViewController)中設置 CAEmitterLayer。如果在項目中使用,有時在自定義視圖(UIView)中加入 CAEmitterLayer 比較合理,例如自定義點贊按鈕,可以精簡控制器的代碼。

下雨動畫效果

這裡的雨勻速下落,雨的密度逐漸變化。

給控制器添加類型為 CAEmitterLayer 的屬性 rainLayer,在 viewDidLoad 方法中對此屬性進行初始化

private var rainLayer: CAEmitterLayer!

private func setupRainLayer() {
    // 粒子發射圖層
    rainLayer = CAEmitterLayer()
    // 發射器形狀為線形,預設發射方向向上
    rainLayer.emitterShape = kCAEmitterLayerLine
    // 從發射器的輪廓發射粒子
    rainLayer.emitterMode = kCAEmitterLayerOutline
    // 優先渲染舊的粒子
    rainLayer.renderMode = kCAEmitterLayerOldestFirst
    // 發射位置
    // 對於線形發射器,線的兩端點分別為
    // (emitterPosition.x - emitterSize.width/2, emitterPosition.y, emitterZPosition)和
    // (emitterPosition.x + emitterSize.width/2, emitterPosition.y, emitterZPosition)
    rainLayer.emitterPosition = CGPoint(x: view.bounds.midX, y: 0)
    // 發射器大小
    rainLayer.emitterSize = CGSize(width: view.bounds.width, height: 0)
    // 粒子生成速率的倍數,一開始不發射,設置為零
    rainLayer.birthRate = 0
    
    // 發射的粒子
    let cell = CAEmitterCell()
    // 粒子顯示的內容,設置CGImage,顯示圖片
    cell.contents = #imageLiteral(resourceName: "Heart_red").cgImage
    // 粒子縮放倍數
    cell.scale = 0.1
    // 粒子壽命,單位是秒
    cell.lifetime = 5
    // 粒子生成速率,單位是個/秒,實際顯示效果要乘以CAEmitterLayer的birthRate
    cell.birthRate = 1000
    // 粒子速度
    cell.velocity = 500
    // 粒子發射角度,正值表示順時針方向
    cell.emissionLongitude = CGFloat.pi
    
    // 圖層要發射1種粒子
    rainLayer.emitterCells = [cell]
    // 添加粒子發射圖層
    view.layer.addSublayer(rainLayer)
}

點擊按鈕開始或停止動畫。用 CABasicAnimation 使粒子生成速率的倍數漸變,達到雨逐漸變大或變小的效果

@IBAction func rainButtonClicked(_ sender: UIButton) {
    // 連續調用此方法會影響雨變大或變小的連貫性,所以禁止連續點擊按鈕
    sender.isUserInteractionEnabled = false
    //  粒子生成速率漸變動畫
    let birthRateAnimation = CABasicAnimation(keyPath: "birthRate")
    birthRateAnimation.duration = 3
    if rainLayer.birthRate == 0 {
        // 雨變大
        birthRateAnimation.fromValue = 0
        birthRateAnimation.toValue = 1
        rainLayer.birthRate = 1
    } else {
        // 雨變小
        birthRateAnimation.fromValue = 1
        birthRateAnimation.toValue = 0
        rainLayer.birthRate = 0
    }
    // 加入動畫
    rainLayer.add(birthRateAnimation, forKey: "birthRate")
    // 動畫時長過後恢復按鈕可點擊狀態
    DispatchQueue.main.asyncAfter(deadline: .now() + birthRateAnimation.duration) { [weak self] in
        guard self != nil else { return }
        sender.isUserInteractionEnabled = true
    }
}

發射一圈粒子動畫效果

給控制器添加類型為 CAEmitterLayer 的屬性 centerHeartLayer,在 viewDidLoad 方法中對此屬性進行初始化

private var centerHeartLayer: CAEmitterLayer!

private func setupCenterHeartLayer() {
    centerHeartLayer = CAEmitterLayer()
    // 發射器形狀為圓形,預設向四周發射粒子
    centerHeartLayer.emitterShape = kCAEmitterLayerCircle
    centerHeartLayer.emitterMode = kCAEmitterLayerOutline
    centerHeartLayer.renderMode = kCAEmitterLayerOldestFirst
    // 發射器位置
    // 對於圓形發射器
    // 圓心位於(emitterPosition.x, emitterPosition.y, emitterZPosition)
    // 半徑為emitterSize.width
    centerHeartLayer.emitterPosition = CGPoint(x: view.bounds.midX, y: view.bounds.midY)
    centerHeartLayer.emitterSize = centerHeartButton.frame.size
    centerHeartLayer.birthRate = 0
    
    let cell = CAEmitterCell()
    cell.contents = #imageLiteral(resourceName: "Heart_red").cgImage
    cell.lifetime = 1
    cell.birthRate = 2000
    cell.scale = 0.05
    // 粒子縮放倍數每秒減小0.02,粒子逐漸縮小
    cell.scaleSpeed = -0.02
    // 粒子透明度每秒減小1,粒子逐漸變透明
    cell.alphaSpeed = -1
    cell.velocity = 30
    
    centerHeartLayer.emitterCells = [cell]
    view.layer.addSublayer(centerHeartLayer)
}

點擊按鈕開始動畫

@IBAction func centerHeartButtonClicked(_ sender: UIButton) {
    sender.isUserInteractionEnabled = false
    // 設置動畫開始時間,否則會有太多粒子
    centerHeartLayer.beginTime = CACurrentMediaTime()
    // 開始生成粒子
    centerHeartLayer.birthRate = 1
    // 一段時間後停止生成粒子
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
        guard let strongSelf = self else { return }
        strongSelf.centerHeartLayer.birthRate = 0
    }
    DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
        guard self != nil else { return }
        sender.isUserInteractionEnabled = true
    }
}

向上發射一個粒子動畫效果

給控制器添加類型為 CAEmitterLayer 的屬性 leftHeartLayer,在 viewDidLoad 方法中對此屬性進行初始化

private var leftHeartLayer: CAEmitterLayer!

private func setupLeftHeartLayer() {
    leftHeartLayer = CAEmitterLayer()
    // 點狀發射器,預設發射方向向右
    // 這句可以省略,點狀是預設值
    leftHeartLayer.emitterShape = kCAEmitterLayerPoint
    // 從發射器中的一點發射粒子
    // 這句可以省略,是預設值
    leftHeartLayer.emitterMode = kCAEmitterLayerVolume
    leftHeartLayer.renderMode = kCAEmitterLayerOldestFirst
    // 發射器位置
    // 對於點狀發射器,發射點在(emitterPosition.x, emitterPosition.y, emitterZPosition)
    leftHeartLayer.emitterPosition = CGPoint(x: view.bounds.midX * 0.5, y: view.bounds.midY)
    leftHeartLayer.birthRate = 0
    
    let cell = CAEmitterCell()
    cell.contents = #imageLiteral(resourceName: "Heart_red").cgImage
    cell.scale = 0.5
    cell.lifetime = 1
    // 1秒發射1個粒子
    cell.birthRate = 1
    cell.alphaSpeed = -1
    cell.velocity = 50
    cell.emissionLongitude = -CGFloat.pi / 2
    
    leftHeartLayer.emitterCells = [cell]
    view.layer.addSublayer(leftHeartLayer)
}

點擊按鈕開始動畫

@IBAction func leftHeartButtonClicked(_ sender: UIButton) {
    sender.isUserInteractionEnabled = false
    // 從上1秒開始動畫,使按鈕點擊後立即發射粒子
    leftHeartLayer.beginTime = CACurrentMediaTime() - 1
    leftHeartLayer.birthRate = 1
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
        guard let strongSelf = self else { return }
        strongSelf.leftHeartLayer.birthRate = 0
    }
    DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
        guard self != nil else { return }
        sender.isUserInteractionEnabled = true
    }
}

向上發射幾個粒子動畫效果

給控制器添加類型為 CAEmitterLayer 的屬性 rightHeartLayer,在 viewDidLoad 方法中對此屬性進行初始化

private var rightHeartLayer: CAEmitterLayer!

private func setupRightHeartLayer() {
    rightHeartLayer = CAEmitterLayer()
    rightHeartLayer.renderMode = kCAEmitterLayerOldestFirst
    rightHeartLayer.emitterPosition = CGPoint(x: view.bounds.midX * 1.5, y: view.bounds.midY)
    rightHeartLayer.birthRate = 0
    
    let cell = CAEmitterCell()
    cell.contents = #imageLiteral(resourceName: "Heart_red").cgImage
    cell.scale = 0.5
    cell.lifetime = 1
    cell.birthRate = 5
    cell.alphaSpeed = -1
    cell.velocity = 50
    cell.emissionLongitude = -CGFloat.pi / 2
    // 粒子發射角度的變化範圍
    cell.emissionRange = CGFloat.pi / 4
    
    rightHeartLayer.emitterCells = [cell]
    view.layer.addSublayer(rightHeartLayer)
}

點擊按鈕開始動畫

@IBAction func rightHeartButtonClicked(_ sender: UIButton) {
    sender.isUserInteractionEnabled = false
    // 1秒發射5個粒子,0.2秒發射1個粒子,從上0.2秒開始動畫,使按鈕點擊後立即發射粒子
    rightHeartLayer.beginTime = CACurrentMediaTime() - 0.2
    rightHeartLayer.birthRate = 1
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) { [weak self] in
        guard let strongSelf = self else { return }
        strongSelf.rightHeartLayer.birthRate = 0
    }
    DispatchQueue.main.asyncAfter(deadline: .now() + 1.6) { [weak self] in
        guard self != nil else { return }
        sender.isUserInteractionEnabled = true
    }
}

拋物線粒子動畫效果

實現拋物線動畫需要給粒子加上重力加速度。此外,這裡還加入粒子旋轉效果,同時發射兩種粒子。

給控制器添加類型為 CAEmitterLayer 的屬性 gravityLayer,在 viewDidLoad 方法中對此屬性進行初始化

private var gravityLayer: CAEmitterLayer!

private func setupGravityLayer() {
    gravityLayer = CAEmitterLayer()
    gravityLayer.renderMode = kCAEmitterLayerOldestFirst
    gravityLayer.emitterPosition = CGPoint(x: 0, y: view.bounds.maxY)
    gravityLayer.birthRate = 0
    
    let cell = CAEmitterCell()
    cell.contents = #imageLiteral(resourceName: "Heart_red").cgImage
    cell.scale = 0.5
    cell.lifetime = 10
    cell.alphaSpeed = -0.1
    cell.birthRate = 10
    cell.velocity = 100
    // y軸方法的加速度,模擬重力加速度
    cell.yAcceleration = 20
    cell.emissionLongitude = -CGFloat.pi / 4
    cell.emissionRange = CGFloat.pi / 4
    // 粒子旋轉角速度,單位是弧度/秒,正值表示順時針旋轉
    // 這句可以省略,預設值是零
    cell.spin = 0
    // 粒子旋轉角速度變化範圍
    cell.spinRange = CGFloat.pi * 2
    
    let cell2 = CAEmitterCell()
    cell2.contents = #imageLiteral(resourceName: "Heart_blue").cgImage
    cell2.scale = 0.3
    cell2.lifetime = 20
    cell2.alphaSpeed = -0.05
    cell2.birthRate = 5
    cell2.velocity = 135
    cell2.yAcceleration = 20
    cell2.emissionLongitude = -CGFloat.pi / 4
    cell2.emissionRange = CGFloat.pi / 4
    cell2.spin = 0
    cell2.spinRange = CGFloat.pi * 2
    
    // 圖層要發射2種粒子
    gravityLayer.emitterCells = [cell, cell2]
    view.layer.addSublayer(gravityLayer)
}

點擊開始或停止動畫

@IBAction func gravityButtonClicked(_ sender: UIButton) {
    if gravityLayer.birthRate == 0 {
        gravityLayer.beginTime = CACurrentMediaTime()
        gravityLayer.birthRate = 1
    } else {
        gravityLayer.birthRate = 0
    }
}

以上是動畫的實現方法,代碼已上傳 GitHub:https://github.com/Silence-GitHub/CoreAnimationDemo

轉載請註明出處:http://www.cnblogs.com/silence-cnblogs/p/6971533.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 作者:Antonio Leiva 時間:Jun 6, 2017 原文鏈接:https://antonioleiva.com/interfaces-kotlin/ 與Java相比,Kotlin介面允許你重用更多的代碼。 原因非常簡單:你能夠向你的介面加代碼。如果你已經試用過Java8,這非常類似。 能 ...
  • 瞭解這一章節,需要先瞭解LayoutInflater這個工具類,我以前分析過:http://www.cnblogs.com/kezhuang/p/6978783.html Window是Activity類中的一個全局變數,Window的作用是輔助Activity(也有可能是其他組件,本章拿Activ ...
  • LayoutInflater是用來解析XML佈局文件,然後生成對象的ViewTree的工具類。是這個工具類的存在,才能讓我們寫起Layout來那麼省勁。 我們接下來進去刨析,看看裡邊的奧秘 我們在使用這個類的時候,通常都是像上面這樣寫,首先通過from函數獲取對象,在調用inflate方法,來生成相 ...
  • Android中整個的View的組裝是採用組合模式。 ViewGroup就相當與樹根,各種Layout就相當於枝幹,各種子View,就相當於樹葉。 至於View類。我們就當它是個種子吧。哈哈! ViewGroup屬於樹根,可以生長數很多枝幹(繼承自定義Layout)而枝幹上有可以長出很多葉子(Tex ...
  • Runtime學習 應用源碼學習   Runtime源碼分析,帶你瞭解OC實現過程。其中參考了大量的大神的代碼以及文獻,裡面也有個人的見解,歡迎拍磚,歡迎交流。 兩種常見使用場景 根據調試信息,發現兩者的區別是: 第一種進入到 第二種繞一個遠路,先初始化 兩者最終進入到如下方法 ...
  • Android實現定時任務一般會使用以上(Handler Timer Thread AlarmManager CountDownTimer)五種方式。當然還有很多組合使用(比如Handler+Thread 比如Handler類自帶的postDelyed 比如Handler+Timer+TimerTa ...
  • 簡單的說,就是當dispatchTouchEvent在進行事件分發的時候,只有前一個事件(如ACTION_DOWN)返回true,才會收到ACTION_MOVE和ACTION_UP的事件。 dispatchTouchEvent 和 onTouchEvent 可以通過return true 消費事件, ...
  • 在WWDC 2017開發者大會上,蘋果宣佈了一系列新的面向開發者的機器學習 API,包括面部識別的視覺 API、自然語言處理 API,這些 API 集成了蘋果所謂的 Core ML 框架。Core ML 的核心是加速在 iPhone、iPad、Apple Watch 上的人工智慧任務,支持深度神經網 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...