像 iOS10 音樂播放器一樣自定義轉(zhuǎn)場動畫

蘋果在 iOS10 里重新設計了音樂播放器(Music),當時在設計圈子還是個不小的事情讥电。對于我個人而言蹂窖,很喜歡它的「正在播放」界面的轉(zhuǎn)場方式。最近打算對 OneShare 進行最后的升級恩敌,正好借鑒了這個轉(zhuǎn)場瞬测。發(fā)現(xiàn)步驟雖然不難,但還是有點繁瑣纠炮,有些細節(jié)需要注意一下月趟。

在 iOS 中,自定轉(zhuǎn)場是通過實現(xiàn)協(xié)議 UIViewControllerTransitioningDelegate 來實現(xiàn)的恢口。協(xié)議中提供了 TransitionAnimator(轉(zhuǎn)場動畫)孝宗、InteractiveAnimator(轉(zhuǎn)場交互)和 PresentationController(視圖層級控制)相關的方法。

// TransitionAnimator(轉(zhuǎn)場動畫)
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source;
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed;

// InteractiveAnimator(轉(zhuǎn)場交互)
- (id<UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id<UIViewControllerAnimatedTransitioning>)animator;
- (id<UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id<UIViewControllerAnimatedTransitioning>)animator;

// PresentationController(視圖層級控制)
- (UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source;

大多數(shù)情況下耕肩,我們只會用 TransitionAnimator 那兩個方法來實現(xiàn)轉(zhuǎn)場動畫因妇。再復雜一點问潭,我們希望實現(xiàn)自定手勢交互的時候沙峻,就需要重寫 InteractiveAnimator 那兩個方法了。分析蘋果的交互两芳,會發(fā)現(xiàn)它還修改了視圖層級的關系摔寨。所以接下來模仿此交互的步驟大概就是:

  1. 實現(xiàn) UIViewControllerAnimatedTransitioning 自定義轉(zhuǎn)場動畫竖螃;
  2. 實現(xiàn) UIPresentationController 自定義視圖控制器的層級表現(xiàn)淑廊;
  3. 實現(xiàn) UIViewControllerInteractiveTransitioning 自定義交互方式。

所以首先在遵守 UIViewControllerTransitioningDelegate 協(xié)議的 AnimatorController 中特咆,直接通過 UIViewanimateWithDuration 方法去自定義轉(zhuǎn)場動畫即可季惩,這一步并沒什么難度。

接下來實現(xiàn)視圖層級控制之前腻格,首先需要將被推出的視圖(這里是 ModalViewController)的 modalPresentationStyle 設置為自定義(UIModalPresentationCustom)画拾。這樣才會調(diào)用協(xié)議中的 presentationControllerForPresentedViewController 方法。
實現(xiàn) UIPresentationController 時菜职,由于它同時接管了轉(zhuǎn)入(presentation)和轉(zhuǎn)出(dismissal)青抛,所以要在步驟 1 的基礎上增加一個轉(zhuǎn)出動畫。這時可以另外新建一個類來處理轉(zhuǎn)出動畫酬核,也可以直接在上面那個 animateTransition: 中實現(xiàn)蜜另,我使用的時后者。

switch (self.transitionType) {

    case AnimatorDismiss: {
        [UIView animateWithDuration:[self transitionDuration:transitionContext]
                            animations:^{
                            // your animation
                            } completion:^(BOOL finished) {
                                [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
                            }];
        break;
    };

    case AnimatorPresent: {
        [[transitionContext containerView] addSubview:toViewController.view];
        // your variable
        [UIView animateWithDuration:[self transitionDuration:transitionContext] 
                            animations:^{
                            // your animation
                        }completion:^(BOOL finished) {
                            [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
        }];
        break;
    };
}

最后就是實現(xiàn)交互了嫡意,因為是計劃打算使用下拉手勢举瑰,所以自定義的 AnimatorInteractive 是繼承的 UIPercentDrivenInteractiveTransition,通過百分比來控制視圖的動效蔬螟。這里要注意在重寫協(xié)議中的 interactionControllerForDismissal 方法時嘶居,不是通過手勢轉(zhuǎn)出的時候,要返回 nil 促煮,否則協(xié)議不會去調(diào)用 animateTransition:邮屁。

- (id<UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id<UIViewControllerAnimatedTransitioning>)animator {
    return self.dismissInteractor.interactionInProgress ? self.dismissInteractor : nil;
}

另外由于在轉(zhuǎn)場中使用了 CGAffineTransformMakeScale 轉(zhuǎn)入,所以在轉(zhuǎn)出時菠齿,需要設置 toViewController.view.transform = CGAffineTransformIdentity 佑吝。這時候遇到了個麻煩,在使用下拉手勢的時候绳匀,父視圖在交互過程中芋忿,就已經(jīng)完成整個變化炸客,導致取消下拉的時候,也不會復原戈钢。因為沒有找到解決辦法痹仙,仔細觀察了下蘋果的交互,發(fā)現(xiàn)也在下拉的時候父試圖也沒有動效殉了,所以猜測沒有直接解決辦法开仰,最后就改成了音樂播放器這樣的實現(xiàn)方式

這里提一句在使用 Swift 實現(xiàn)的時候薪铜,iOS10 上通過下拉手勢關閉試圖沒成功的時候众弓,ModalViewController 可能不會復原,這可能是蘋果在 iOS10 改了 UIView.animateTransition 實現(xiàn)的原因隔箍,用 UIViewPropertyAnimatorrunningPropertyAnimator 方法替代就可以了谓娃,在之前的一篇博客中提到過。

到這兒基本是就完了蜒滩,還有最后一點修飾工作滨达,就是 StatusBar 的樣式。其實設置起來不麻煩俯艰,在 ModalViewController 里如下設置即可:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.modalPresentationCapturesStatusBarAppearance = YES;
    // Do any additional setup after loading the view.
    ...
}

- (UIStatusBarStyle)preferredStatusBarStyle {
    return UIStatusBarStyleLightContent;
}

但在實際操作中遇到了一點麻煩弦悉,因為不知道什么時候把 Info.plist 里的 UIViewControllerBasedStatusBarAppearance 設置為 NO 了,所以一直沒有成功蟆炊,最后看到這篇文章才意識到問題稽莉。總結(jié)起來決定 StatusBar 樣式的優(yōu)先級依次是:

Info.plist > UINavigationController > Modal 中的 preferredStatusBarStyle

此文示例代碼:iOS10ModelPresent

參考鏈接:

Creating Custom UIViewController Transitions

Status bar colours: Everything there is to know

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末涩搓,一起剝皮案震驚了整個濱河市污秆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌昧甘,老刑警劉巖良拼,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異充边,居然都是意外死亡庸推,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門浇冰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來贬媒,“玉大人,你說我怎么就攤上這事肘习〖食耍” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵漂佩,是天一觀的道長脖含。 經(jīng)常有香客問我罪塔,道長,這世上最難降的妖魔是什么养葵? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任征堪,我火速辦了婚禮,結(jié)果婚禮上关拒,老公的妹妹穿的比我還像新娘佃蚜。我一直安慰自己,他們只是感情好夏醉,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布爽锥。 她就那樣靜靜地躺著涌韩,像睡著了一般畔柔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上臣樱,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天靶擦,我揣著相機與錄音,去河邊找鬼雇毫。 笑死玄捕,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的棚放。 我是一名探鬼主播枚粘,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼飘蚯!你這毒婦竟也來了馍迄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤局骤,失蹤者是張志新(化名)和其女友劉穎攀圈,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體峦甩,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡赘来,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了凯傲。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片犬辰。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖冰单,靈堂內(nèi)的尸體忽然破棺而出忧风,到底是詐尸還是另有隱情,我是刑警寧澤球凰,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布狮腿,位于F島的核電站腿宰,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏缘厢。R本人自食惡果不足惜吃度,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望贴硫。 院中可真熱鬧椿每,春花似錦、人聲如沸英遭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽挖诸。三九已至汁尺,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間多律,已是汗流浹背痴突。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留狼荞,地道東北人辽装。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像相味,于是被迫代替她去往敵國和親拾积。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容