欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

在iOS中實現(xiàn)谷歌滅霸彩蛋的完整示例

 更新時間:2019年05月06日 09:18:28   作者:potato04  
這篇文章主要給大家介紹了關于如何在iOS中實現(xiàn)谷歌滅霸彩蛋的相關資料,文中通過示例代碼介紹的非常詳細,對各位iOS開發(fā)者們具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧

前言

最近上映的復仇者聯(lián)盟4據(jù)說沒有片尾彩蛋,不過谷歌幫我們做了。只要在谷歌搜索滅霸,在結果的右側點擊無限手套,你將化身為滅霸,其中一半的搜索結果會化為灰燼消失...那么這么酷的動畫在iOS中可以實現(xiàn)嗎?答案是肯定的。整個動畫主要包含以下幾部分:響指動畫、沙化消失以及背景音效和復原動畫,讓我們分別來看看如何實現(xiàn)。

圖1 左為沙化動畫,右為復原動畫

響指動畫

Google的方法是利用了48幀合成的一張Sprite圖進行動畫的:

圖2 響指Sprite圖片

原始圖片中48幅全部排成一行,這里為了顯示效果截成2行

iOS 中通過這張圖片來實現(xiàn)動畫并不難。CALayer有一個屬性contentsRect,通過它可以控制內容顯示的區(qū)域,而且是Animateable的。它的類型是CGRect,默認值為(x:0.0, y:0.0, width:1.0, height:1.0),它的單位不是常見的Point,而是單位坐標空間,所以默認值顯示100%的內容區(qū)域。新建Sprite播放視圖層AnimatableSpriteLayer:

class AnimatableSpriteLayer: CALayer {
 private var animationValues = [CGFloat]()
 convenience init(spriteSheetImage: UIImage, spriteFrameSize: CGSize ) {
 self.init()
 //1
 masksToBounds = true
 contentsGravity = CALayerContentsGravity.left
 contents = spriteSheetImage.cgImage
 bounds.size = spriteFrameSize
 //2
 let frameCount = Int(spriteSheetImage.size.width / spriteFrameSize.width)
 for frameIndex in 0..<frameCount {
  animationValues.append(CGFloat(frameIndex) / CGFloat(frameCount))
 }
 }
 
 func play() {
 let spriteKeyframeAnimation = CAKeyframeAnimation(keyPath: "contentsRect.origin.x")
 spriteKeyframeAnimation.values = animationValues
 spriteKeyframeAnimation.duration = 2.0
 spriteKeyframeAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
 //3
 spriteKeyframeAnimation.calculationMode = CAAnimationCalculationMode.discrete
 add(spriteKeyframeAnimation, forKey: "spriteKeyframeAnimation")
 }
}

//1: masksToBounds = true和contentsGravity = CALayerContentsGravity.left是為了當前只顯示Sprite圖的第一幅畫面

//2: 根據(jù)Sprite圖大小和每幅畫面的大小計算出畫面數(shù)量,預先計算出每幅畫面的contentsRect.origin.x偏移量

//3: 這里是關鍵,指定關鍵幀動畫的calculationMode為discrete確保關鍵幀動畫依次使用values中指定的關鍵幀值進行變化,而不是默認情況下采用線性插值進行過渡,來個對比圖可能比較容易理解:

圖3 左邊為離散模式,右邊為默認的線性模式

沙化消失

這個效果是整個動畫較難的部分,Google的實現(xiàn)很巧妙,它將需要沙化消失內容的html通過html2canvas渲染成canvas,然后將其轉換為圖片后的每一個像素點隨機地分配到32塊canvas中,最后對每塊畫布進行隨機地移動和旋轉即達到了沙化消失的效果。

像素處理

新建自定義視圖 DustEffectView,這個視圖的作用是用來接收圖片并將其進行沙化消失。首先創(chuàng)建函數(shù)createDustImages,它將一張圖片的像素隨機分配到32張等待動畫的圖片上:

class DustEffectView: UIView {
 private func createDustImages(image: UIImage) -> [UIImage] {
 var result = [UIImage]()
 guard let inputCGImage = image.cgImage else {
  return result
 }
 //1
 let colorSpace = CGColorSpaceCreateDeviceRGB()
 let width = inputCGImage.width
 let height = inputCGImage.height
 let bytesPerPixel = 4
 let bitsPerComponent = 8
 let bytesPerRow = bytesPerPixel * width
 let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Little.rawValue
 
 guard let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo) else {
  return result
 }
 context.draw(inputCGImage, in: CGRect(x: 0, y: 0, width: width, height: height))
 guard let buffer = context.data else {
  return result
 }
 let pixelBuffer = buffer.bindMemory(to: UInt32.self, capacity: width * height)
 //2
 let imagesCount = 32
 var framePixels = Array(repeating: Array(repeating: UInt32(0), count: width * height), count: imagesCount)
 for column in 0..<width {
  for row in 0..<height {
  let offset = row * width + column
  //3
  for _ in 0...1 { 
   let factor = Double.random(in: 0..<1) + 2 * (Double(column)/Double(width))
   let index = Int(floor(Double(imagesCount) * ( factor / 3)))
   framePixels[index][offset] = pixelBuffer[offset]
  }
  }
 }
 //4
 for frame in framePixels {
  let data = UnsafeMutablePointer(mutating: frame)
  guard let context = CGContext(data: data, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo) else {
  continue
  }
  result.append(UIImage(cgImage: context.makeImage()!, scale: image.scale, orientation: image.imageOrientation))
 }
 return result
 }
}

//1: 根據(jù)指定格式創(chuàng)建位圖上下文,然后將輸入的圖片繪制上去之后獲取其像素數(shù)據(jù)

//2: 創(chuàng)建像素二維數(shù)組,遍歷輸入圖片每個像素,將其隨機分配到數(shù)組32個元素之一的相同位置。隨機方法有點特別,原始圖片左邊的像素只會分配到前幾張圖片,而原始圖片右邊的像素只會分配到后幾張。

圖4 上部分為原始圖片,下部分為像素分配后的32張圖片依次顯示效果

//3: 這里循環(huán)2次將像素分配兩次,可能 Google 覺得只分配一遍會造成像素比較稀疏。個人認為在移動端,只要一遍就好了。

//4: 創(chuàng)建32張圖片并返回

添加動畫

Google的實現(xiàn)是給canvas中css的transform屬性設置為rotate(deg) translate(px, px) rotate(deg),值都是隨機生成的。如果你對CSS的動畫不熟悉,那你會覺得在iOS中只要添加三個CABasicAnimation然后將它們添加到AnimationGroup就好了嘛,實際上并沒有那么簡單... 因為CSS的transform中后一個變換函數(shù)是基于前一個變換后的新transform坐標系。假如某張圖片的動畫樣式是這樣的:rotate(90deg) translate(0px, 100px) rotate(-90deg) 直覺告訴我應該是旋轉著向下移動100px,然而在CSS中的元素是這么運動的:

圖5 CSS中transform多值動畫

第一個rotate和translate決定了最終的位置和運動軌跡,至于第二個rotate作用,只是疊加第一個rotate的值作為最終的旋轉弧度,這里剛好為0也就是不旋轉。那么在iOS中該如何實現(xiàn)相似的運動軌跡呢?可以利用UIBezierPath, CAKeyframeAnimation的屬性path可以指定這個UIBezierPath為動畫的運動軌跡。確定起點和實際終點作為貝塞爾曲線的起始點和終止點,那么如何確定控制點?好像可以將“預想”的終點(下圖中的(0,-1))作為控制點。

圖6 將“預想”的終點作為控制點的貝塞爾曲線,看起來和CSS中的運動軌跡差不多

擴展問題

通過文章中描述的方式生成的貝塞爾曲線是否與CSS中的動畫軌跡完全一致呢?

現(xiàn)在可以給視圖添加動畫了:

 let layer = CALayer()
 layer.frame = bounds
 layer.contents = image.cgImage
 self.layer.addSublayer(layer)
 let centerX = Double(layer.position.x)
 let centerY = Double(layer.position.y)
 let radian1 = Double.pi / 12 * Double.random(in: -0.5..<0.5)
 let radian2 = Double.pi / 12 * Double.random(in: -0.5..<0.5)
 let random = Double.pi * 2 * Double.random(in: -0.5..<0.5)
 let transX = 60 * cos(random)
 let transY = 30 * sin(random)
 //1: 
 // x' = x*cos(rad) - y*sin(rad)
 // y' = y*cos(rad) + x*sin(rad)
 let realTransX = transX * cos(radian1) - transY * sin(radian1)
 let realTransY = transY * cos(radian1) + transX * sin(radian1)
 let realEndPoint = CGPoint(x: centerX + realTransX, y: centerY + realTransY)
 let controlPoint = CGPoint(x: centerX + transX, y: centerY + transY)
 //2:
 let movePath = UIBezierPath()
 movePath.move(to: layer.position)
 movePath.addQuadCurve(to: realEndPoint, controlPoint: controlPoint)
 let moveAnimation = CAKeyframeAnimation(keyPath: "position")
 moveAnimation.path = movePath.cgPath
 moveAnimation.calculationMode = .paced
 //3:   
 let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation")
 rotateAnimation.toValue = radian1 + radian2
 let fadeOutAnimation = CABasicAnimation(keyPath: "opacity")
 fadeOutAnimation.toValue = 0.0
 let animationGroup = CAAnimationGroup()
 animationGroup.animations = [moveAnimation, rotateAnimation, fadeOutAnimation]
 animationGroup.duration = 1
 //4:
 animationGroup.beginTime = CACurrentMediaTime() + 1.35 * Double(i) / Double(imagesCount)
 animationGroup.isRemovedOnCompletion = false
 animationGroup.fillMode = .forwards
 layer.add(animationGroup, forKey: nil)

//1: 實際的偏移量旋轉了radian1弧度,這個可以通過公式x' = x*cos(rad) - y*sin(rad), y' = y*cos(rad) + x*sin(rad)算出

//2: 創(chuàng)建UIBezierPath并關聯(lián)到CAKeyframeAnimation中

//3: 兩個弧度疊加作為最終的旋轉弧度

//4: 設置CAAnimationGroup的開始時間,讓每層Layer的動畫延遲開始

結尾

到這里,谷歌滅霸彩蛋中較復雜的技術點均已實現(xiàn)。如果您感興趣,完整的代碼(包含音效和復原動畫)可以通過文章開頭的鏈接進行查看,可以嘗試將沙化圖片的數(shù)量從32提高至更多,效果會越好,內存也會消耗更多 :-D。

示例代碼下載

參考資料

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對腳本之家的支持。

相關文章

  • 詳解在iOS App中自定義和隱藏狀態(tài)欄的方法

    詳解在iOS App中自定義和隱藏狀態(tài)欄的方法

    這篇文章主要介紹了在iOS App中自定義和隱藏狀態(tài)欄的方法,在頂部時某些狀況下即用應用內的狀態(tài)欄覆蓋系統(tǒng)本身的,代碼示例為Objective-C語言,需要的朋友可以參考下
    2016-03-03
  • iOS 攔截重定向302跳轉的方法詳解

    iOS 攔截重定向302跳轉的方法詳解

    這篇文章主要介紹了iOS 攔截重定向302跳轉的方法詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • 關于iOS獲取屬性你真的了解嗎?

    關于iOS獲取屬性你真的了解嗎?

    這篇文章主要給大家介紹了關于iOS取屬性的相關資料,當說到取屬性,相信很多的iOS開發(fā)者們會說出很多,但你就真的理解嗎?下面就來詳細,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-12-12
  • Objective C從遠程url下載圖片方法匯總

    Objective C從遠程url下載圖片方法匯總

    本文給大家分享了2則使用Objective C從遠程url下載圖片的方法,都是個人項目中使用的,匯總下推薦給大家,有需要的小伙伴可以參考下。
    2015-05-05
  • iOS中5種圖片縮略技術及性能的深入探討

    iOS中5種圖片縮略技術及性能的深入探討

    縮略圖是各位iOS開發(fā)者們在日常工作中經(jīng)常會遇到的一個需求,下面這篇文章主要給大家介紹了關于iOS中5種圖片縮略技術及性能的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2018-06-06
  • iOS開發(fā)之運動事件和遠程控制

    iOS開發(fā)之運動事件和遠程控制

    在iOS中事件分為三類:觸摸事件:通過觸摸、手勢進行觸發(fā)(例如手指點擊、縮放),運動事件:通過加速器進行觸發(fā)(例如手機晃動),遠程控制事件:通過其他遠程設備觸發(fā)(例如耳機控制按鈕)今天我們來詳細探討下運動事件和遠程控制
    2016-04-04
  • iOS開發(fā)之通過銀行卡號獲取所屬銀行名稱

    iOS開發(fā)之通過銀行卡號獲取所屬銀行名稱

    本文給大家分享一段代碼關于ios通過銀行卡號獲取所屬銀行名稱,代碼簡單易懂,在項目開發(fā)中經(jīng)常會遇到這樣的功能,需要的朋友一起學習吧
    2016-11-11
  • iOS實現(xiàn)一個可以在屏幕中自由移動的按鈕

    iOS實現(xiàn)一個可以在屏幕中自由移動的按鈕

    經(jīng)常在手機上看到可以隨意移動的按鈕,正巧最近工作遇到了這個需求,索性就寫一個,下面這篇文章主要給大家介紹了利用iOS實現(xiàn)一個可以在屏幕中自由移動的按鈕的相關資料,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-07-07
  • iOS利用MJRefresh實現(xiàn)自定義刷新動畫效果

    iOS利用MJRefresh實現(xiàn)自定義刷新動畫效果

    本文主要介紹iOS 利用MJRefresh實現(xiàn)自定義動畫的上拉刷新下拉加載效果,要想實現(xiàn)此功能,首先得有一套load的圖片數(shù)組。接下來通過本文給大家詳解介紹實現(xiàn)過程
    2017-02-02
  • 詳解如何使用ReactiveObjC

    詳解如何使用ReactiveObjC

    RAC 指的就是 RactiveCocoa ,是 Github 的一個開源框架,能夠通過信號提供大量方便的事件處理方案,讓我們更簡單粗暴地去處理事件,現(xiàn)在分為 ReactiveObjC(OC) 和 ReactiveSwift(swift)。本文將詳細介紹如何使用ReactiveObjC。
    2021-06-06

最新評論