在iOS中实现谷歌灭霸彩蛋的完整示例

前言

最近上映的复仇者联盟4据说没有片尾彩蛋,不过谷歌帮我们做了。只要在谷歌搜索灭霸,在结果的右侧点击无限手套,你将化身为灭霸,其中一半的搜索结果会化为灰烬消失...那么这么酷的动画在iOS中可以实现吗?答案是肯定的。整个动画主要包含以下几部分:响指动画、沙化消失以及背景音效和复原动画,让我们分别来看看如何实现。

图1 左为沙化动画,右为复原动画

响指动画

Google的方法是利用了48帧合成的一张Sprite图进行动画的:

图4 上部分为原始图片,下部分为像素分配后的32张图片依次显示效果

//3: 这里循环2次将像素分配两次,可能 Google 觉得只分配一遍会造成像素比较稀疏。个人认为在移动端,只要一遍就好了。

//4: 创建32张图片并返回

添加动画

Google的实现是给canvas中css的transform属性设置为rotate(deg) translate(px,px) rotate(deg),值都是随机生成的。如果你对CSS的动画不熟悉,那你会觉得在iOS中只要添加三个CABasicAnimation然后将它们添加到AnimationGroup就好了嘛,实际上并没有那么简单... 因为CSS的transform中后一个变换函数是基于前一个变换后的新transform坐标系。假如某张图片的动画样式是这样的:rotate(90deg) translate(0px,100px) rotate(-90deg) 直觉告诉我应该是旋转着向下移动100px,然而在CSS中的元素是这么运动的:

图6 将“预想”的终点作为控制点的贝塞尔曲线,看起来和CSS中的运动轨迹差不多

扩展问题

通过文章中描述的方式生成的贝塞尔曲线是否与CSS中的动画轨迹完全一致呢?

现在可以给视图添加动画了:

 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: 创建UIBezierPath并关联到CAKeyframeAnimation中

//3: 两个弧度叠加作为最终的旋转弧度

//4: 设置CAAnimationGroup的开始时间,让每层Layer的动画延迟开始

结尾

到这里,谷歌灭霸彩蛋中较复杂的技术点均已实现。如果您感兴趣,完整的代码(包含音效和复原动画)可以通过文章开头的链接进行查看,可以尝试将沙化图片的数量从32提高至更多,效果会越好,内存也会消耗更多 :-D。

示例代码下载

参考资料

  • www.calayer.com/core-animat…
  • stackoverflow.com/questions/3…
  • weibo.com/1727858283/…

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。

以上是来客网为你收集整理的在iOS中实现谷歌灭霸彩蛋的完整示例全部内容,希望文章能够帮你解决在iOS中实现谷歌灭霸彩蛋的完整示例所遇到的程序开发问题。

如果觉得来客网网站内容还不错,欢迎将来客网网站推荐给程序员好友。