Album Animation Part III: Interactive UICollectionViewLayout Transition

系列重写了,这篇文章留在这里记录下错误思路。

系列前两篇文章在此:Part I, Part II。三天前还信心满满地要把 Interactive Push Transition 弄出来,到此刻不得不声明,用尽了我能尝试的办法,没能解决。囧rz。暂时找不到解决办法,先记录下思路,以便日后复盘。

在使用 pinch 手势 push toViewController 的 transition 中发生的事件顺序如下:
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 动画开始
7.toVC.collectionView:cellForItemAtIndexPath: //cell 开始在屏幕上
8.toVC.pinch.End and contextTransition.completeTransition() //push transitin 结束
9.toVC.viewDidAppear()

WWDC13 Session 218: Custom Transitions Using View Controllers 中工程师一再强调不保证 transition 中 viewDidAppear() 发生在 viewWillAppear() 之后,之前墨客的开发者也发过一篇文章讲过这个问题,不过目前来看这个顺序还算稳定。

Part II 中可知,若是 push transition 中有动画没有发生在 AnimationController 的- animateTransition:中,那么终止交互后无法维持这个动画的继续或是返回。将一个 UICollectionviewController push transition 变成可交互的困难在于在无法在 AnimationController 的- animateTransition:发生前获取目标视图中的 Cells,也就无法将 Cell 上的动画放入- animateTransition:以进行交互控制(在 pop 时就不存在这个问题,因此此时 Cells 可以使用 collectionView.visibleCells() 来获取,所以 pop 的交互化就很简单了)。于是思路转换为在手势控制过程中让其布局跟随手势更新,在手势结束后更新布局为需要的布局并将这个过程动画化。这个思路将 cell 的动画的控制权从由交互控制器 InteractiveController 转移到了手势中。此时有两种方案:

  1. UICollectionViewTransitionLayout: iOS 7 推出的新类,用于对布局更新进行动画,在 WWDC13 Session 218: Custom Transitions Using View Controllers 中跟着其他三种视图转换机制一起隆重推出,看起来是个合适的选择。
    UICollectionView layout transition

    在手势更新过程中只要更新第一个方法返回的UICollectionViewTransitionLayouttransitionProgress属性值就可以对整个过程进行控制。在一个 viewDidAppear 后的 collectionView 使用该类进行布局转换是非常方便以及简单的,一切如你想象的那样。然而,在 push transition 中,这个类无法正常工作。
  2. 手动对布局进行更新:这个听起来更靠谱一点,除了有点恼人的布局动画的性能除外,在结束手势时布局动画会播放两次,就坏在这里了,百思不得其解。手动更新布局有个很容易掉进去的坑:更新布局后,使用 toVC.collectionViewLayout 得到的仅仅是 toVC 初始化时的布局,而不是更新后的布局,必须通过 toVC.collectionView.collectionViewLayout 来获取。这个坑可坑死我了。一直纳闷为啥有时候能手势驱动布局更新,有时候又不能,因为我没注意到这两个方法的区别。

这里有个环节我的代码里可能会存在问题,就是手势的建立。下面代码做的事就是在 pinch 手势的 Begin 状态下,实例化目标控制器 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)
                    /***进行一些配置***/    
                    //必须将当前的手势添加到toView,在 toVC 自行添加的手势在 push transition 中无法被识别                    
                    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
            }
        }     
    }
}

上述过程中将 fromView 中的 pinch 手势复制到了 toView 中,因为在 toView 的初始化过程中自行添加的手势在 push transition 中无法被识别。另外当前的 pinch 手势在 fromView 中很难检测到 Ended 或是 Cancelled状态,大概是隔了一层 toView 的缘故,而在 toView 中却检测不到 Begin 状态,Begin 状态的缺失让UICollectionViewTransitionLayout的初始化工作也就是调用- startInteractiveTransitionToCollectionViewLayout:completion:有点困难。不过这个好解决,让这个方法只运行一次的方法很多,接下来只要在手势的 Changed, Ended, Cancelled 的状态中走一下 UICollectionViewTransitionLayout 的标准流程就可以了。但问题来了,这个类似乎很脆弱,得小心翼翼地使用 pinch,你能看到预期的效果,一旦你快速地使用,基本上就会出现以下错误,google 无果。
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'the collection was not prepared for an interactive transition. see startInteractiveTransitionToCollectionViewLayout:completion:'

Photos 和 Paper 里的 pinch 手势驱动 push transition 就是我想要的效果,前两者基本从一个 Stack 布局的 CollectionView 转换到最常见的 FlowLayout 布局的 CollectionView,这个方案在WWDC13 Session 218中演示过,demo 代码在此: ViewTransition Demo Code in WWDC13 Session 218。但我着手解决的这个问题和它们有点不一样,我想要的是从 toView 出现后进行布局转换,然而却不遂我愿,也许这条路走不通,等我有心情了再试试。

今天在微博上看到 CKWaveCollectionViewTransition 这个效果,主要是 cell 之间的时间差调节得非常惊艳,之前我也有类似的调整,但基本上看不出效果来,看人家的代码,用于调整时间差的算法还是很复杂的,反正扫一眼代码就晕菜了。虽然动画时间有点长,但这个惊艳的画面表现我忍了。动画在质量而不在数量,相比之下,我尝试做了好几种效果,却差了老远。

在摸索过程中,也许有很多地方我不了解而犯了错,就比如动画放在哪儿执行,就只能在- viewDidLoad, - viewWillAppear:, - viewWillDisappear:中挨个试;还有出现那个问题 google 无果后,我也没有手段去探知哪个环节出错,尽管从函数调用帧上看到出错的地方似乎是内部的实现问题,但这种束手无策的境地让我很不安,是时候好好学习 debug 了。前年实习的时候,我的上司面对一些问题总是会"异想天开"地在一些环节上下手,在我看来不了解系统的相关流程,这么瞎搞效率很低,但有不少时候我的上司这么瞎搞搞问题还真解决了。唉,踢一脚有时候就能解决大部分的电器问题。

另外,看了人家的代码,能直接拿来用,而我的则不行,要好好设计下代码才行。

目前这个问题我实在有点厌烦了,绞尽脑汁,就差那么一点点,然而路还是被堵死了,这种无望烦躁在长时间盯着电脑精神迷糊或是 Xcode 对 Swift 的糟糕支持下更加严重了,我要转移下注意力。

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

推荐阅读更多精彩内容

  • 前言的前言 唐巧前辈在微信公众号「iOSDevTips」以及其博客上推送了我的文章后,我的 Github 各项指标...
    VincentHK阅读 5,360评论 3 44
  • 效果预览: 前言 苹果自家应用 Photos 里点击相册后的动画是非常精妙的,而且是可交互的。我有类似的动画需求,...
    seedante阅读 5,757评论 3 39
  • iOS视图控制器详解 视图控制器中的视图显示在屏幕上有两种方式:最主要的方式是内嵌在容器控制器中,比如 UINav...
    coder_feng阅读 11,218评论 2 12
  • 下午三点,一个又黑又壮、穿着绿色护士服的彪形大汉带我去手术室,他先带我到护士站打了一针阿托品。这家伙块头虽大,却很...
    杨爱民阅读 547评论 6 5
  • 若有明天 我想像掠过的流星般灿烂 若有明天 我想一直注视银河、月亮和樱花 若有明天 我想焚尽曾经流淌笔下的痴情诗篇...
    芊里行云阅读 182评论 1 2