系列重寫了戈抄,這篇文章留在這里記錄下錯(cuò)誤思路苏章。
系列前兩篇文章在此:Part I, Part II皇帮。三天前還信心滿滿地要把 Interactive Push Transition 弄出來(lái)刽严,到此刻不得不聲明寸潦,用盡了我能嘗試的辦法,沒(méi)能解決琉历。囧rz坠七。暫時(shí)找不到解決辦法水醋,先記錄下思路,以便日后復(fù)盤彪置。
在使用 pinch 手勢(shì) push toViewController 的 transition 中發(fā)生的事件順序如下:
1.fromVC.pinch and initial.toVC
2.toVC.viewDidLoad()
3.navigationController.push(toVC)
4.ask navigation transition delegate for: animation controller, interactive controller
5.toVC.viewWillAppear()
6.AnimationController.animateTransition(contextTransition) //Transition 動(dòng)畫開(kāi)始
7.toVC.collectionView:cellForItemAtIndexPath: //cell 開(kāi)始在屏幕上
8.toVC.pinch.End and contextTransition.completeTransition() //push transitin 結(jié)束
9.toVC.viewDidAppear()
在 WWDC13 Session 218: Custom Transitions Using View Controllers 中工程師一再?gòu)?qiáng)調(diào)不保證 transition 中 viewDidAppear() 發(fā)生在 viewWillAppear() 之后拄踪,之前墨客的開(kāi)發(fā)者也發(fā)過(guò)一篇文章講過(guò)這個(gè)問(wèn)題,不過(guò)目前來(lái)看這個(gè)順序還算穩(wěn)定悉稠。
由 Part II 中可知宫蛆,若是 push transition 中有動(dòng)畫沒(méi)有發(fā)生在 AnimationController 的- animateTransition:
中,那么終止交互后無(wú)法維持這個(gè)動(dòng)畫的繼續(xù)或是返回的猛。將一個(gè) UICollectionviewController push transition 變成可交互的困難在于在無(wú)法在 AnimationController 的- animateTransition:
發(fā)生前獲取目標(biāo)視圖中的 Cells,也就無(wú)法將 Cell 上的動(dòng)畫放入- animateTransition:
以進(jìn)行交互控制(在 pop 時(shí)就不存在這個(gè)問(wèn)題想虎,因此此時(shí) Cells 可以使用 collectionView.visibleCells() 來(lái)獲取卦尊,所以 pop 的交互化就很簡(jiǎn)單了)。于是思路轉(zhuǎn)換為在手勢(shì)控制過(guò)程中讓其布局跟隨手勢(shì)更新舌厨,在手勢(shì)結(jié)束后更新布局為需要的布局并將這個(gè)過(guò)程動(dòng)畫化岂却。這個(gè)思路將 cell 的動(dòng)畫的控制權(quán)從由交互控制器 InteractiveController 轉(zhuǎn)移到了手勢(shì)中。此時(shí)有兩種方案:
-
UICollectionViewTransitionLayout
: iOS 7 推出的新類裙椭,用于對(duì)布局更新進(jìn)行動(dòng)畫躏哩,在 WWDC13 Session 218: Custom Transitions Using View Controllers 中跟著其他三種視圖轉(zhuǎn)換機(jī)制一起隆重推出,看起來(lái)是個(gè)合適的選擇揉燃。
在手勢(shì)更新過(guò)程中只要更新第一個(gè)方法返回的UICollectionViewTransitionLayout
的transitionProgress
屬性值就可以對(duì)整個(gè)過(guò)程進(jìn)行控制扫尺。在一個(gè) viewDidAppear 后的 collectionView 使用該類進(jìn)行布局轉(zhuǎn)換是非常方便以及簡(jiǎn)單的,一切如你想象的那樣炊汤。然而正驻,在 push transition 中,這個(gè)類無(wú)法正常工作抢腐。 - 手動(dòng)對(duì)布局進(jìn)行更新:這個(gè)聽(tīng)起來(lái)更靠譜一點(diǎn)姑曙,除了有點(diǎn)惱人的布局動(dòng)畫的性能除外,在結(jié)束手勢(shì)時(shí)布局動(dòng)畫會(huì)播放兩次迈倍,就壞在這里了伤靠,百思不得其解。手動(dòng)更新布局有個(gè)很容易掉進(jìn)去的坑:更新布局后啼染,使用 toVC.collectionViewLayout 得到的僅僅是 toVC 初始化時(shí)的布局宴合,而不是更新后的布局,必須通過(guò) toVC.collectionView.collectionViewLayout 來(lái)獲取提完。這個(gè)坑可坑死我了形纺。一直納悶為啥有時(shí)候能手勢(shì)驅(qū)動(dòng)布局更新,有時(shí)候又不能徒欣,因?yàn)槲覜](méi)注意到這兩個(gè)方法的區(qū)別逐样。
這里有個(gè)環(huán)節(jié)我的代碼里可能會(huì)存在問(wèn)題,就是手勢(shì)的建立。下面代碼做的事就是在 pinch 手勢(shì)的 Begin 狀態(tài)下脂新,實(shí)例化目標(biāo)控制器 toVC 并 push挪捕。
func handlePinchGestureAction(gesture:UIPinchGestureRecognizer){
let scale = gesture.scale
if scale >= 1.0{
if let indexPath = collectionView?.indexPathForItemAtPoint(gesture.locationInView(collectionView)){
switch gesture.state{
case .Began:
interactive = true
let cell = collectionView?.cellForItemAtIndexPath(indexPath)
let cellReferencePoint = cell?.convertPoint(CGPointMake(10, 10), toView: self.collectionView!)
let layoutAttributes = self.collectionView!.layoutAttributesForItemAtIndexPath(indexPath)
let imageOriginInSuperView = self.collectionView!.convertPoint((layoutAttributes?.frame.origin)!, toView: self.collectionView!.superview)
if let toVC = self.storyboard?.instantiateViewControllerWithIdentifier("AlbumVC") as? SDEAlbumViewController{
let initialLayout = PushTransitionInitialStateFlowLayout(cell!.convertPoint(CGPointMake(85, 85), toView: self.collectionView!))
toVC.collectionView?.setCollectionViewLayout(initialLayout, animated: true)
/***進(jìn)行一些配置***/
//必須將當(dāng)前的手勢(shì)添加到toView,在 toVC 自行添加的手勢(shì)在 push transition 中無(wú)法被識(shí)別
gesture.addTarget(toVC, action: "handlePushTransitionActionWithPinchGesture:")
toVC.view.addGestureRecognizer(gesture)
toVC.interactivePushTransitionDelegate = interactivePushTransitionDelegate
self.navigationController?.delegate = self
self.navigationController?.pushViewController(toVC, animated: true)
}
case .Changed:
interactive = false
default:
interactive = false
}
}
}
}
上述過(guò)程中將 fromView 中的 pinch 手勢(shì)復(fù)制到了 toView 中争便,因?yàn)樵?toView 的初始化過(guò)程中自行添加的手勢(shì)在 push transition 中無(wú)法被識(shí)別级零。另外當(dāng)前的 pinch 手勢(shì)在 fromView 中很難檢測(cè)到 Ended 或是 Cancelled狀態(tài),大概是隔了一層 toView 的緣故滞乙,而在 toView 中卻檢測(cè)不到 Begin 狀態(tài)奏纪,Begin 狀態(tài)的缺失讓UICollectionViewTransitionLayout
的初始化工作也就是調(diào)用- startInteractiveTransitionToCollectionViewLayout:completion:
有點(diǎn)困難。不過(guò)這個(gè)好解決斩启,讓這個(gè)方法只運(yùn)行一次的方法很多序调,接下來(lái)只要在手勢(shì)的 Changed, Ended, Cancelled 的狀態(tài)中走一下 UICollectionViewTransitionLayout
的標(biāo)準(zhǔn)流程就可以了。但問(wèn)題來(lái)了兔簇,這個(gè)類似乎很脆弱发绢,得小心翼翼地使用 pinch,你能看到預(yù)期的效果垄琐,一旦你快速地使用边酒,基本上就會(huì)出現(xiàn)以下錯(cuò)誤,google 無(wú)果狸窘。
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'the collection was not prepared for an interactive transition. see startInteractiveTransitionToCollectionViewLayout:completion:'
Photos 和 Paper 里的 pinch 手勢(shì)驅(qū)動(dòng) push transition 就是我想要的效果墩朦,前兩者基本從一個(gè) Stack 布局的 CollectionView 轉(zhuǎn)換到最常見(jiàn)的 FlowLayout 布局的 CollectionView,這個(gè)方案在WWDC13 Session 218中演示過(guò)朦前,demo 代碼在此: ViewTransition Demo Code in WWDC13 Session 218介杆。但我著手解決的這個(gè)問(wèn)題和它們有點(diǎn)不一樣,我想要的是從 toView 出現(xiàn)后進(jìn)行布局轉(zhuǎn)換韭寸,然而卻不遂我愿春哨,也許這條路走不通,等我有心情了再試試恩伺。
今天在微博上看到 CKWaveCollectionViewTransition 這個(gè)效果赴背,主要是 cell 之間的時(shí)間差調(diào)節(jié)得非常驚艷,之前我也有類似的調(diào)整晶渠,但基本上看不出效果來(lái)凰荚,看人家的代碼,用于調(diào)整時(shí)間差的算法還是很復(fù)雜的褒脯,反正掃一眼代碼就暈菜了便瑟。雖然動(dòng)畫時(shí)間有點(diǎn)長(zhǎng),但這個(gè)驚艷的畫面表現(xiàn)我忍了番川。動(dòng)畫在質(zhì)量而不在數(shù)量到涂,相比之下脊框,我嘗試做了好幾種效果,卻差了老遠(yuǎn)践啄。
在摸索過(guò)程中浇雹,也許有很多地方我不了解而犯了錯(cuò),就比如動(dòng)畫放在哪兒執(zhí)行屿讽,就只能在- viewDidLoad
, - viewWillAppear:
, - viewWillDisappear:
中挨個(gè)試昭灵;還有出現(xiàn)那個(gè)問(wèn)題 google 無(wú)果后,我也沒(méi)有手段去探知哪個(gè)環(huán)節(jié)出錯(cuò)伐谈,盡管從函數(shù)調(diào)用幀上看到出錯(cuò)的地方似乎是內(nèi)部的實(shí)現(xiàn)問(wèn)題烂完,但這種束手無(wú)策的境地讓我很不安,是時(shí)候好好學(xué)習(xí) debug 了衩婚。前年實(shí)習(xí)的時(shí)候窜护,我的上司面對(duì)一些問(wèn)題總是會(huì)"異想天開(kāi)"地在一些環(huán)節(jié)上下手,在我看來(lái)不了解系統(tǒng)的相關(guān)流程非春,這么瞎搞效率很低,但有不少時(shí)候我的上司這么瞎搞搞問(wèn)題還真解決了缓屠。唉奇昙,踢一腳有時(shí)候就能解決大部分的電器問(wèn)題。
另外敌完,看了人家的代碼储耐,能直接拿來(lái)用,而我的則不行滨溉,要好好設(shè)計(jì)下代碼才行什湘。
目前這個(gè)問(wèn)題我實(shí)在有點(diǎn)厭煩了,絞盡腦汁晦攒,就差那么一點(diǎn)點(diǎn)闽撤,然而路還是被堵死了,這種無(wú)望煩躁在長(zhǎng)時(shí)間盯著電腦精神迷糊或是 Xcode 對(duì) Swift 的糟糕支持下更加嚴(yán)重了脯颜,我要轉(zhuǎn)移下注意力哟旗。