先上效果:
Github 地址:UIView Refactor Destruct Animation
本動(dòng)畫的出現(xiàn)是由于前幾天出現(xiàn)的牛人@ibireme呆瞻,看看人家博客的質(zhì)量還有開源的幾個(gè)庫譬淳,完全就是航空母艦戰(zhàn)斗群啊建芙,我這里根本就是小舢板泉褐,我所有的文章加起來和人家比起來完全就是渣渣规哪。就在本文即將發(fā)布的時(shí)候,這位又祭出了一篇大殺器文章熄云。唯一值得欣慰的是膨更,人家在 iOS 界浸淫了至少三年了,不過大部分人的三年是什么水平缴允,從開始接觸 iOS 開發(fā)到現(xiàn)在也有一年半了荚守,目前的水平,看人家寫的庫心虛得很啊练般,大新聞不是那么矗漾。好了,好好學(xué)習(xí)踢俄。小知識正式開始放送:
功能
做成了擴(kuò)展缩功,依然是一行代碼調(diào)用的熟悉風(fēng)格。缺陷是不直接支持 Auto Layout都办,因?yàn)槟阍O(shè)置的約束條件對我來說完全未知嫡锌,直接設(shè)置 frame 與 Auto Layout 有點(diǎn)沖突虑稼,你得先用 Auto Layout 的手段移動(dòng)視圖后不觸發(fā)重新布局的情況下再調(diào)用這個(gè)動(dòng)畫。
重組/分解動(dòng)畫都支持:
1.重組方向:橫向势木、縱向以及對角線(從左至右)蛛倦。
2.自定義重組動(dòng)畫時(shí)間:這個(gè)看上有點(diǎn)奇怪,哪個(gè)動(dòng)畫不能指定時(shí)間啊啦桌,不過這里是群體動(dòng)畫溯壶,提供這個(gè)選項(xiàng)還是有必要的。
3.自定義碎片的大小: 通過設(shè)定 ratio 值來指定碎片相對源視圖的比例甫男,寬度和高度都應(yīng)用這個(gè)比例且改,你可以自己
支持兩種。
只有重組動(dòng)畫支持:
1.自定義閃光顏色:不設(shè)定值時(shí)則沒有閃光特效板驳,這個(gè)純粹是我的惡趣味又跛,不打開還能提升性能。
2.自定義碎片出現(xiàn)的區(qū)域:不設(shè)定值時(shí)默認(rèn)為源視圖區(qū)域的兩倍大小
參數(shù)意義不一一解釋了若治,想要的話去看源碼里的注釋好了慨蓝。
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 中函數(shù)的默認(rèn)值參數(shù)的好處
這個(gè)好處是無意中發(fā)現(xiàn)的,之前也知道默認(rèn)值參數(shù)這個(gè)特性端幼,但沒意識到減少參數(shù)輸入的巨大好處礼烈。這個(gè)動(dòng)畫想讓所有的視圖都能使用必然是通過擴(kuò)展來實(shí)現(xiàn),而擴(kuò)展里沒法添加存儲屬性的婆跑,那就只能通過關(guān)聯(lián)對象來實(shí)現(xiàn)了此熬。當(dāng)我決定讓這個(gè)動(dòng)畫能夠進(jìn)行各種定制時(shí),發(fā)現(xiàn)自定義的參數(shù)有點(diǎn)多洽蛀。讓我在擴(kuò)展里添加六個(gè)關(guān)聯(lián)對象摹迷,那代碼量,我是不想干的郊供。如果不使用關(guān)聯(lián)對象峡碉,只能在函數(shù)里加上七個(gè)可選參數(shù)了,調(diào)用時(shí)那畫面不敢想象驮审,發(fā)現(xiàn)定制一個(gè)參數(shù)居然要另外填寫六個(gè)nil
時(shí)估計(jì)要哭了鲫寄,不能接受。
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 里那樣函數(shù)能接受自定義數(shù)量的參數(shù)該多好疯淫,默認(rèn)值參數(shù)就能實(shí)現(xiàn)這個(gè)特性地来。升級到 Xcode 7.1.1 后,發(fā)現(xiàn) Xcode 已經(jīng)能夠自動(dòng)提示不帶默認(rèn)值參數(shù)的函數(shù)版本了熙掺,當(dāng)然不知道是不是我記錯(cuò)了未斑,因?yàn)樵谏壡拔覜]發(fā)現(xiàn)這個(gè),我是在擴(kuò)展了參數(shù)個(gè)數(shù)并添加了默認(rèn)值時(shí)發(fā)現(xiàn)原來的調(diào)用居然能用時(shí)發(fā)現(xiàn)這個(gè)好處的币绩。除了第一個(gè)是我自己封裝的蜡秽,第二個(gè)是 Xcode 給出的便捷調(diào)用原型府阀。
這個(gè)特性的使用規(guī)則如下:在默認(rèn)值參數(shù)段與其他類型參數(shù)段維持整體的相對位置的情況下,默認(rèn)值參數(shù)輸入順序不強(qiáng)求按照函數(shù)原型里的參數(shù)順序芽突,而且不限定個(gè)數(shù)试浙。
這個(gè)時(shí)候估計(jì)你要使壞了,默認(rèn)值參數(shù)與其他參數(shù)混搭行不行寞蚌,比如默認(rèn)值參數(shù)夾在其他參數(shù)中間田巴?沒問題,隨便混搭挟秤,只要調(diào)用時(shí)維持它們的相對位置就好壹哺,太方便了!
混搭風(fēng)函數(shù)原型:
func refactorWithNewFrame(destinationFrame: CGRect?艘刚,direction: SDERefactorDirection = .Vertical, shiningColor: UIColor?, enableBigRegion: Bool = false, refactorTime animationTime: NSTimeInterval = 1.0, partionRatio ratio: CGFloat = 0.05, jumpRect: CGRect?)
調(diào)用時(shí)斗躏,可以這樣寫:
refactorWithNewFrame(nil,shiningColor: nil, enableBigRegion: true, jumpRect: nil)
refactorWithNewFrame(nil,shiningColor: nil, jumpRect: nil)
上面的示例參數(shù)太復(fù)雜。寫個(gè)簡單的例子昔脯,定義下面這個(gè)函數(shù):
func sampleMethod(A: nil, B:String = "B", C:String = "C", D:nil, E:Int = E)
調(diào)用時(shí):
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)
總之,默認(rèn)值參數(shù)可以當(dāng)做不存在笛臣,如果想提供默認(rèn)值以外的參數(shù)云稚,在正確的相對位置添加默認(rèn)值參數(shù)即可。如果有多個(gè)默認(rèn)值參數(shù)相鄰沈堡,這幾個(gè)默認(rèn)值參數(shù)的順序可以任意静陈。但這個(gè)優(yōu)點(diǎn)對于依賴自動(dòng)補(bǔ)全的人來說估計(jì)意識不到他們不需要輸入那么多參數(shù),得引導(dǎo)一下诞丽。
隨機(jī)數(shù)
要想讓這個(gè)重組動(dòng)畫看起來有點(diǎn)炫酷有很重要的一點(diǎn):獲取隨機(jī)數(shù)鲸拥,這是第一個(gè)攔路虎,推薦這樣來獲取一個(gè)隨機(jī)整數(shù):
Int(UInt32(arc4random()) % UInt32(<someInt>))
至于原因僧免,來看隨機(jī)數(shù)生成和 subcode: 0xe7ffdefe刑赶。
重組動(dòng)畫的設(shè)計(jì)初衷是讓視圖碎片隨機(jī)在某片區(qū)域內(nèi),但是你會發(fā)現(xiàn)所有的碎片幾乎是均勻地分布在這片區(qū)域內(nèi)懂衩,看上去一點(diǎn)也不隨機(jī)撞叨,而且這樣的分布讓動(dòng)畫看上去很無趣。最后我只好用多重隨機(jī)數(shù)來編造碎片出現(xiàn)的位置浊洞,但還是不符合我心目中隨機(jī)的效果牵敷。在我們心目中隨機(jī)就是雜亂無章,但使用上面的代碼得到的隨機(jī)數(shù)實(shí)際上很有規(guī)律法希,不幸的是不是我需要的規(guī)律枷餐。這里不僅要隨機(jī),而且還需要一個(gè)有規(guī)律的分布苫亦,我不知道真正的隨機(jī)的分布規(guī)律是怎樣的(概率統(tǒng)計(jì)早忘光了)毛肋,但一個(gè)均勻分布實(shí)在是太無趣了怨咪,自己造一個(gè)正太分布啥的好像還有點(diǎn)難度,我反正不會村生。
關(guān)于隨機(jī)數(shù)惊暴,推薦一篇非常有意思的文章:偽隨機(jī)的上位和真隨機(jī)的逆襲。
性能優(yōu)劣:UIView Animation VS Core Animation
我本以為兩者的性能差不多的趁桃,但在碎片數(shù)量超過1000左右時(shí)辽话,兩者的性能差距還是挺大的。在 ipad mini 1和2代上卫病,僅僅是移動(dòng)位置這個(gè)動(dòng)畫油啤,在碎片數(shù)量超過1000時(shí),使用 Core Animation 實(shí)現(xiàn)時(shí)重組過程大概只能看到一半蟀苛;而數(shù)量超過10000左右時(shí)益咬, UIView Animation 的性能也大幅下降。如果你要分割成超過10000時(shí)帜平,你得尋求其他手段了幽告,比如 OpenGL,正如 StarWar 這個(gè)動(dòng)畫里做的那樣裆甩,或者你可以考慮新的 Metal 框架來實(shí)現(xiàn)冗锁,這里有篇教程。
陰影
由于我想要光影特效嗤栓,最簡單的手段就是通過陰影來表現(xiàn)了冻河。
snapshot.layer.shadowOpacity = 1.0
snapshot.layer.shadowColor = shiningColor.CGColor
snapshot.layer.shadowRadius = 15.0
上面三個(gè)屬性就能造出陰影了,但不知道什么時(shí)候起茉帅,你搜到的各種陰影設(shè)置可能都包含了一些其他設(shè)置叨叙,比如:
snapshot.layer.masksToBounds = false
這個(gè)選項(xiàng)默認(rèn)是 false,多次一舉堪澎,設(shè)置為 true 后陰影特效就消失了擂错,至于為什么,看這里全封。如果你不幸拷貝了一段錯(cuò)誤的代碼马昙,你可能會花費(fèi)幾個(gè)小時(shí)來排除陰影消失的問題。
如果對陰影的半徑進(jìn)行動(dòng)畫刹悴,你的最佳選擇并不是shadowRadius
屬性行楞,而是shadowOpacity
屬性。對前者進(jìn)行動(dòng)畫土匀,效果會很難看子房,而后者才是你想要的。但這兩者進(jìn)行動(dòng)畫的前提卻是矛盾的,同時(shí)這兩者進(jìn)行動(dòng)畫的效果會抵消效果证杭。
有時(shí)候你想要炫目一點(diǎn)的光影特效田度,于是使用明亮的顏色,拼命加大shadowRadius
屬性的值解愤,卻發(fā)現(xiàn)沒什么用镇饺,來試試這個(gè),指定陰影的路徑送讲,炫目程度大增:
//指定一個(gè)比自身尺寸大一點(diǎn)的路徑
let bigRect = CGRectInset(snapshot.bounds, -20, -20)
snapshot.layer.shadowPath = UIBezierPath(rect: bigRect).CGPath//shadowPath 是在自身坐標(biāo)系內(nèi)進(jìn)行計(jì)算的奸笤,別用 frame
如果你對這個(gè)光環(huán)的形狀不是很滿意,給我來個(gè)圓潤點(diǎn)的光環(huán):
//生成一個(gè)橢圓形的路徑哼鬓,而圓形就是一個(gè)特殊的橢圓
let ovalRect = CGRectInset(snapshot.bounds, -20, -20)
let shadowPath = UIBezierPath(ovalInRect: ovalRect)
snapshot.layer.shadowPath = shadowPath.CGPath
一旦有了陰影监右,你就有了麻煩,它對性能有很大的影響异希,CALayer shadow performance 三個(gè)關(guān)鍵字在 stack overflow 里有非常多的提問健盒。這兩個(gè)提問比較典型:1和2。有些答案適合別人的場景未必適合你称簿,你得多試試扣癣。在碎片數(shù)量很多時(shí),陰影的表現(xiàn)效果不佳憨降,會造成前面的碎片沒有特效搏色。
本來,我還想加點(diǎn)這樣的效果券册,地鐵上經(jīng)常有那種點(diǎn)狀印刷的廣告,那么動(dòng)畫里先生成一個(gè)點(diǎn)陣圖再變成正常的樣子垂涯。模擬那種效果需要圓角矩形烁焙,與陰影的設(shè)置有點(diǎn)沖突,解決手段參考這里:UIView with rounded corners and drop shadow耕赘,但圓角矩形又是一個(gè)性能殺手骄蝇,要解決這個(gè)問題又得花點(diǎn)功夫。對于這個(gè)動(dòng)畫而言有點(diǎn)復(fù)雜了操骡,暫時(shí)放棄這個(gè)效果九火。
還有,關(guān)于 Core Animation 的beginTime
屬性册招,這里也有坑等著你:Time Warp in Animation岔激。如果你想設(shè)置一個(gè) Core Animation 延遲一段時(shí)間執(zhí)行,千萬記得加上CACurrentMediaTime()
:
let xxxAnimation = CABasicAnimation(keyPath: xxx)
xxxAnimation.beginTime = CACurrentMediaTime() + delayTime
雖然都是老坑是掰,但這塊的坑還真是多虑鼎,我被浪費(fèi)的時(shí)間也是特別多。
對于使用 CALayer 進(jìn)行動(dòng)畫,強(qiáng)烈推薦:
1.CALayer Animation
2.LayerPlayer app
3.LayerPlayer source code
Github 地址:UIView Refactor Destruct Animation
這才是原來的文章本體:瞎扯扯
這個(gè)動(dòng)畫是看到 iOS 處理圖片的一些小 Tips 這篇文章里提到漸進(jìn)式顯示下載中的圖片時(shí)想到的炫彩,后來這個(gè)動(dòng)畫完成后匾七,發(fā)現(xiàn)不是很合適用在這里。于是江兢,我做了一些改動(dòng)變成了現(xiàn)在的樣子昨忆,可以用來替代移動(dòng)的動(dòng)畫效果,后來為了實(shí)現(xiàn)在 UICollectionView 刪除 cell 時(shí)的動(dòng)畫效果添加了分解效果杉允,這個(gè)分解動(dòng)畫也可以用于視圖的消失邑贴。
動(dòng)畫的實(shí)現(xiàn),就跟你想的一樣夺颤,很簡單的痢缎,截圖后分割移動(dòng)加上五毛閃光特效,大頭是用于調(diào)整順序的算法世澜,就這些根本沒必要寫篇文章独旷。但我在嘗試各種效果的時(shí)候發(fā)現(xiàn)了一些坑,雖然大部分是老坑寥裂,但坑起你來沒商量嵌洼,記錄一下。雖然這個(gè)動(dòng)畫本身的技術(shù)含量并不高封恰,但可玩性很大麻养,你想要碎片怎么移動(dòng)得炫酷,調(diào)整下算法就好了诺舔。完成動(dòng)畫后鳖昌,我尋找了一些合適的使用場景,發(fā)現(xiàn) UICollectionView 的插入刪除元素時(shí)這個(gè)動(dòng)畫效果還是挺合適的低飒,這個(gè)是基于 objc.io 的 Collection View 動(dòng)畫一文進(jìn)行的改造许昨,文章在這里:。
近來中國 iOS 界似乎很熱衷寫交互動(dòng)畫褥赊,發(fā)現(xiàn)微博上很多人求業(yè)界知名人士轉(zhuǎn)發(fā)這方面的輪子糕档。當(dāng)然,我最近寫了幾個(gè)動(dòng)畫拌喉,對這方面的關(guān)注也多了些速那,也許是孕婦效應(yīng)吧。這樣帶來的好處是尿背,程序員都開始注重提升交互效果了端仰,有更多輪子可以用了,是不是代表我們的應(yīng)用的體驗(yàn)會更好田藐。放心我肯定說錯(cuò)了榆俺,畢竟寫動(dòng)畫是最容易得星星的手段,而且程序員的設(shè)計(jì)水平應(yīng)該是比不上公司的設(shè)計(jì)師的,放心好了茴晋,在應(yīng)用的設(shè)計(jì)這方面程序員肯定沒話語權(quán)啦陪捷,而且程序員連完成需求都沒時(shí)間別說其他的了。日常應(yīng)用大多滿足功能是最重要的诺擅,交互其次市袖,而且,并不是炫酷好看才是好的交互烁涌,絕大部分場景并不需要華麗的動(dòng)畫苍碟,系統(tǒng)提供的動(dòng)畫能滿足大部分需求,合適的動(dòng)畫才是好動(dòng)畫。
對于動(dòng)畫,賣相相當(dāng)重要娇妓,我花了很多心思的轉(zhuǎn)場動(dòng)畫無論從技術(shù)上還是創(chuàng)意上都比那個(gè)卡片動(dòng)畫好金麸,但因?yàn)闆]有好看的的 UI 設(shè)計(jì)建炫,也沒有炫酷的原型動(dòng)畫,賣相太差,沒吸引什么多少 star。非常高興這個(gè)轉(zhuǎn)場動(dòng)畫得到了 iOS Animations By Emails 網(wǎng)站的收錄仗扬,同時(shí)收錄了一些近期大熱的動(dòng)畫,一看就我的賣相最差蕾额,哭死早芭。這期收錄了一個(gè)爆炸效果,從實(shí)現(xiàn)思路上看诅蝶,本文的效果和那個(gè)還是挺相近的退个,畢竟都是一個(gè)類型的;最后一個(gè)好像沒法輕易看到效果调炬,就沒看了帜乞;收錄中最贊的是近期大熱的 StarWars.iOS 動(dòng)畫,無論 UI 設(shè)計(jì)筐眷,還是創(chuàng)意本身與場景的結(jié)合,還是技術(shù)實(shí)現(xiàn)都非常精彩习柠。創(chuàng)作這個(gè)動(dòng)畫的公司還開源了很多優(yōu)秀的動(dòng)畫匀谣,創(chuàng)意、UI 以及技術(shù)都非常好资溃,值得關(guān)注武翎。像 StarWars.iOS 這個(gè)動(dòng)畫,最大的挑戰(zhàn)是性能優(yōu)化溶锭,要是我宝恶,估計(jì)還找不到方向來解決,一看人家的博客,發(fā)現(xiàn)好多看不懂垫毙。相比國外優(yōu)秀的動(dòng)畫效果霹疫,國內(nèi)網(wǎng)站收錄的庫里大部分的動(dòng)畫很多都放些美女圖,高下立判综芥,不過丽蝎,我認(rèn)真想了下,可能是美女的質(zhì)量太差才導(dǎo)致我反感的膀藐。但客觀地講屠阻,見到的動(dòng)畫效果在創(chuàng)意、UI 設(shè)計(jì)上國內(nèi)相比國外還是差太多额各。大多程序員做的動(dòng)畫界面太差国觉,像我做的轉(zhuǎn)場動(dòng)畫,原創(chuàng)的虾啦,沒有了漂亮的原型動(dòng)畫加持麻诀,自己做的簡陋界面太難看,根本沒人氣缸逃,這塊得加強(qiáng)针饥。當(dāng)然,這個(gè)動(dòng)畫做出來對我來說主要是探索轉(zhuǎn)場這一塊需频,技術(shù)的提升才是最重要的丁眼。你給了星星的動(dòng)畫除了好看有多少你自己使用了,背后的技術(shù)你又了解了多少昭殉。