重组/分解动画 UIView Refactor/Destruct Animation

先上效果:


All Actions.5.1M.gif
Horizontal Refactor.gif

Github 地址:UIView Refactor Destruct Animation

本动画的出现是由于前几天出现的牛人@ibireme,看看人家博客的质量还有开源的几个库,完全就是航空母舰战斗群啊,我这里根本就是小舢板,我所有的文章加起来和人家比起来完全就是渣渣。就在本文即将发布的时候,这位又祭出了一篇大杀器文章。唯一值得欣慰的是,人家在 iOS 界浸淫了至少三年了,不过大部分人的三年是什么水平,从开始接触 iOS 开发到现在也有一年半了,目前的水平,看人家写的库心虚得很啊,大新闻不是那么。好了,好好学习。小知识正式开始放送:

功能

做成了扩展,依然是一行代码调用的熟悉风格。缺陷是不直接支持 Auto Layout,因为你设置的约束条件对我来说完全未知,直接设置 frame 与 Auto Layout 有点冲突,你得先用 Auto Layout 的手段移动视图后不触发重新布局的情况下再调用这个动画。

重组/分解动画都支持:
1.重组方向:横向、纵向以及对角线(从左至右)。
2.自定义重组动画时间:这个看上有点奇怪,哪个动画不能指定时间啊,不过这里是群体动画,提供这个选项还是有必要的。
3.自定义碎片的大小: 通过设定 ratio 值来指定碎片相对源视图的比例,宽度和高度都应用这个比例,你可以自己
支持两种。

只有重组动画支持:
1.自定义闪光颜色:不设定值时则没有闪光特效,这个纯粹是我的恶趣味,不打开还能提升性能。
2.自定义碎片出现的区域:不设定值时默认为源视图区域的两倍大小

参数意义不一一解释了,想要的话去看源码里的注释好了。
Refactor API:

theView.refactor()
theView.refactorWithNewFrame(nil, piecesRegion: nil, shiningColor: nil)
theView.refactorWithNewFrame(newFrame, piecesRegion: nil, shiningColor: nil, direction: .Horizontal, refactorTime: 0.6, partionRatio: 0.05, enableBigRegion:false)

Destruct API:

theView.destruct()
theView.destructWithDirection(.Diagonal, animationTime: 0.5, pieceRatio: 0.05)

Swift 中函数的默认值参数的好处

这个好处是无意中发现的,之前也知道默认值参数这个特性,但没意识到减少参数输入的巨大好处。这个动画想让所有的视图都能使用必然是通过扩展来实现,而扩展里没法添加存储属性的,那就只能通过关联对象来实现了。当我决定让这个动画能够进行各种定制时,发现自定义的参数有点多。让我在扩展里添加六个关联对象,那代码量,我是不想干的。如果不使用关联对象,只能在函数里加上七个可选参数了,调用时那画面不敢想象,发现定制一个参数居然要另外填写六个nil时估计要哭了,不能接受。

func refactorWithNewFrame(destinationFrame: CGRect?, piecesRegion jumpRect: CGRect?, shiningColor: UIColor?, direction: SDERefactorDirection = .Horizontal, refactorTime animationTime: NSTimeInterval = 0.6, pieceRatio ratio: CGFloat = 0.05, enableBigRegion: Bool = false)

要是像 python 里那样函数能接受自定义数量的参数该多好,默认值参数就能实现这个特性。升级到 Xcode 7.1.1 后,发现 Xcode 已经能够自动提示不带默认值参数的函数版本了,当然不知道是不是我记错了,因为在升级前我没发现这个,我是在扩展了参数个数并添加了默认值时发现原来的调用居然能用时发现这个好处的。除了第一个是我自己封装的,第二个是 Xcode 给出的便捷调用原型。

自动提示

这个特性的使用规则如下:在默认值参数段与其他类型参数段维持整体的相对位置的情况下,默认值参数输入顺序不强求按照函数原型里的参数顺序,而且不限定个数。

这个时候估计你要使坏了,默认值参数与其他参数混搭行不行,比如默认值参数夹在其他参数中间?没问题,随便混搭,只要调用时维持它们的相对位置就好,太方便了!

混搭风函数原型:

func refactorWithNewFrame(destinationFrame: CGRect?,direction: SDERefactorDirection = .Vertical, shiningColor: UIColor?, enableBigRegion: Bool = false, refactorTime animationTime: NSTimeInterval = 1.0, partionRatio ratio: CGFloat = 0.05, jumpRect: CGRect?)

调用时,可以这样写:

refactorWithNewFrame(nil,shiningColor: nil, enableBigRegion: true, jumpRect: nil)
refactorWithNewFrame(nil,shiningColor: nil, jumpRect: nil)

上面的示例参数太复杂。写个简单的例子,定义下面这个函数:

func sampleMethod(A: nil, B:String = "B", C:String = "C", D:nil, E:Int = E)

调用时:

sampleMethod(nil, D:nil)
sampleMethod(A, B:"BB",D: nil)
sampleMethod(nil, C:"CC", D:D)
sampleMethod(nil, C:"CC", B:"BB", D:D)
sampleMethod(nil, D:DD, E: EE)

总之,默认值参数可以当做不存在,如果想提供默认值以外的参数,在正确的相对位置添加默认值参数即可。如果有多个默认值参数相邻,这几个默认值参数的顺序可以任意。但这个优点对于依赖自动补全的人来说估计意识不到他们不需要输入那么多参数,得引导一下。

随机数

要想让这个重组动画看起来有点炫酷有很重要的一点:获取随机数,这是第一个拦路虎,推荐这样来获取一个随机整数:

Int(UInt32(arc4random()) % UInt32(<someInt>))

至于原因,来看随机数生成subcode: 0xe7ffdefe

重组动画的设计初衷是让视图碎片随机在某片区域内,但是你会发现所有的碎片几乎是均匀地分布在这片区域内,看上去一点也不随机,而且这样的分布让动画看上去很无趣。最后我只好用多重随机数来编造碎片出现的位置,但还是不符合我心目中随机的效果。在我们心目中随机就是杂乱无章,但使用上面的代码得到的随机数实际上很有规律,不幸的是不是我需要的规律。这里不仅要随机,而且还需要一个有规律的分布,我不知道真正的随机的分布规律是怎样的(概率统计早忘光了),但一个均匀分布实在是太无趣了,自己造一个正太分布啥的好像还有点难度,我反正不会。

关于随机数,推荐一篇非常有意思的文章:伪随机的上位和真随机的逆袭

性能优劣:UIView Animation VS Core Animation

我本以为两者的性能差不多的,但在碎片数量超过1000左右时,两者的性能差距还是挺大的。在 ipad mini 1和2代上,仅仅是移动位置这个动画,在碎片数量超过1000时,使用 Core Animation 实现时重组过程大概只能看到一半;而数量超过10000左右时, UIView Animation 的性能也大幅下降。如果你要分割成超过10000时,你得寻求其他手段了,比如 OpenGL,正如 StarWar 这个动画里做的那样,或者你可以考虑新的 Metal 框架来实现,这里有篇教程

阴影

由于我想要光影特效,最简单的手段就是通过阴影来表现了。

snapshot.layer.shadowOpacity = 1.0  
snapshot.layer.shadowColor = shiningColor.CGColor
snapshot.layer.shadowRadius = 15.0

上面三个属性就能造出阴影了,但不知道什么时候起,你搜到的各种阴影设置可能都包含了一些其他设置,比如:

snapshot.layer.masksToBounds = false

这个选项默认是 false,多次一举,设置为 true 后阴影特效就消失了,至于为什么,看这里。如果你不幸拷贝了一段错误的代码,你可能会花费几个小时来排除阴影消失的问题。

如果对阴影的半径进行动画,你的最佳选择并不是shadowRadius属性,而是shadowOpacity属性。对前者进行动画,效果会很难看,而后者才是你想要的。但这两者进行动画的前提却是矛盾的,同时这两者进行动画的效果会抵消效果。

有时候你想要炫目一点的光影特效,于是使用明亮的颜色,拼命加大shadowRadius属性的值,却发现没什么用,来试试这个,指定阴影的路径,炫目程度大增:

//指定一个比自身尺寸大一点的路径
let bigRect = CGRectInset(snapshot.bounds, -20, -20)
snapshot.layer.shadowPath = UIBezierPath(rect: bigRect).CGPath//shadowPath 是在自身坐标系内进行计算的,别用 frame

如果你对这个光环的形状不是很满意,给我来个圆润点的光环:

//生成一个椭圆形的路径,而圆形就是一个特殊的椭圆
let ovalRect = CGRectInset(snapshot.bounds, -20, -20)
let shadowPath = UIBezierPath(ovalInRect: ovalRect)
snapshot.layer.shadowPath = shadowPath.CGPath

一旦有了阴影,你就有了麻烦,它对性能有很大的影响,CALayer shadow performance 三个关键字在 stack overflow 里有非常多的提问。这两个提问比较典型:12。有些答案适合别人的场景未必适合你,你得多试试。在碎片数量很多时,阴影的表现效果不佳,会造成前面的碎片没有特效。

本来,我还想加点这样的效果,地铁上经常有那种点状印刷的广告,那么动画里先生成一个点阵图再变成正常的样子。模拟那种效果需要圆角矩形,与阴影的设置有点冲突,解决手段参考这里:UIView with rounded corners and drop shadow,但圆角矩形又是一个性能杀手,要解决这个问题又得花点功夫。对于这个动画而言有点复杂了,暂时放弃这个效果。

还有,关于 Core Animation 的beginTime属性,这里也有坑等着你:Time Warp in Animation。如果你想设置一个 Core Animation 延迟一段时间执行,千万记得加上CACurrentMediaTime():

let xxxAnimation = CABasicAnimation(keyPath: xxx)
xxxAnimation.beginTime = CACurrentMediaTime() + delayTime

虽然都是老坑,但这块的坑还真是多,我被浪费的时间也是特别多。

对于使用 CALayer 进行动画,强烈推荐:
1.CALayer Animation
2.LayerPlayer app
3.LayerPlayer source code

Github 地址:UIView Refactor Destruct Animation

这才是原来的文章本体:瞎扯扯

这个动画是看到 iOS 处理图片的一些小 Tips 这篇文章里提到渐进式显示下载中的图片时想到的,后来这个动画完成后,发现不是很合适用在这里。于是,我做了一些改动变成了现在的样子,可以用来替代移动的动画效果,后来为了实现在 UICollectionView 删除 cell 时的动画效果添加了分解效果,这个分解动画也可以用于视图的消失。

动画的实现,就跟你想的一样,很简单的,截图后分割移动加上五毛闪光特效,大头是用于调整顺序的算法,就这些根本没必要写篇文章。但我在尝试各种效果的时候发现了一些坑,虽然大部分是老坑,但坑起你来没商量,记录一下。虽然这个动画本身的技术含量并不高,但可玩性很大,你想要碎片怎么移动得炫酷,调整下算法就好了。完成动画后,我寻找了一些合适的使用场景,发现 UICollectionView 的插入删除元素时这个动画效果还是挺合适的,这个是基于 objc.io 的 Collection View 动画一文进行的改造,文章在这里:。

近来中国 iOS 界似乎很热衷写交互动画,发现微博上很多人求业界知名人士转发这方面的轮子。当然,我最近写了几个动画,对这方面的关注也多了些,也许是孕妇效应吧。这样带来的好处是,程序员都开始注重提升交互效果了,有更多轮子可以用了,是不是代表我们的应用的体验会更好。放心我肯定说错了,毕竟写动画是最容易得星星的手段,而且程序员的设计水平应该是比不上公司的设计师的,放心好了,在应用的设计这方面程序员肯定没话语权啦,而且程序员连完成需求都没时间别说其他的了。日常应用大多满足功能是最重要的,交互其次,而且,并不是炫酷好看才是好的交互,绝大部分场景并不需要华丽的动画,系统提供的动画能满足大部分需求,合适的动画才是好动画。

对于动画,卖相相当重要,我花了很多心思的转场动画无论从技术上还是创意上都比那个卡片动画好,但因为没有好看的的 UI 设计,也没有炫酷的原型动画,卖相太差,没吸引什么多少 star。非常高兴这个转场动画得到了 iOS Animations By Emails 网站的收录,同时收录了一些近期大热的动画,一看就我的卖相最差,哭死。这期收录了一个爆炸效果,从实现思路上看,本文的效果和那个还是挺相近的,毕竟都是一个类型的;最后一个好像没法轻易看到效果,就没看了;收录中最赞的是近期大热的 StarWars.iOS 动画,无论 UI 设计,还是创意本身与场景的结合,还是技术实现都非常精彩。创作这个动画的公司还开源了很多优秀的动画,创意、UI 以及技术都非常好,值得关注。像 StarWars.iOS 这个动画,最大的挑战是性能优化,要是我,估计还找不到方向来解决,一看人家的博客,发现好多看不懂。相比国外优秀的动画效果,国内网站收录的库里大部分的动画很多都放些美女图,高下立判,不过,我认真想了下,可能是美女的质量太差才导致我反感的。但客观地讲,见到的动画效果在创意、UI 设计上国内相比国外还是差太多。大多程序员做的动画界面太差,像我做的转场动画,原创的,没有了漂亮的原型动画加持,自己做的简陋界面太难看,根本没人气,这块得加强。当然,这个动画做出来对我来说主要是探索转场这一块,技术的提升才是最重要的。你给了星星的动画除了好看有多少你自己使用了,背后的技术你又了解了多少。

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

推荐阅读更多精彩内容