自定義轉(zhuǎn)場動(dòng)畫非正式翻譯

自定義轉(zhuǎn)場動(dòng)畫

這張圖是自己在翻譯官方文檔Customizing the Transition Animations的總結(jié):

轉(zhuǎn)場動(dòng)畫過程

接下來是漫長的翻譯部分,英文水平有限,有些單詞不知道怎么去表達(dá)(比如persentations,dismissals,chrome等等),各位看官多多指教,在下感激不盡。

自定義轉(zhuǎn)場(過渡)動(dòng)畫

轉(zhuǎn)場動(dòng)畫可提供應(yīng)用程序界面變更的視覺反饋。UIKit提供了一套標(biāo)準(zhǔn)轉(zhuǎn)場樣式,以便在呈現(xiàn)視圖控制器的時(shí)候使用,并且你可以使用自己的自定義轉(zhuǎn)場來補(bǔ)充標(biāo)準(zhǔn)轉(zhuǎn)場。

轉(zhuǎn)場動(dòng)畫序列

轉(zhuǎn)場動(dòng)畫將一個(gè)控制器的內(nèi)容交換為另一個(gè)的內(nèi)容。有兩種類型的轉(zhuǎn)場:presentationsdismissals。一個(gè)presentations轉(zhuǎn)場會(huì)向應(yīng)用程序的視圖控制器層級(jí)添加一個(gè)新的視圖控制器,而dismissal轉(zhuǎn)場會(huì)從層級(jí)中移除一個(gè)或多個(gè)視圖控制器。

實(shí)現(xiàn)轉(zhuǎn)場動(dòng)畫需要許多對(duì)象。UIKit 提供轉(zhuǎn)場中涉及的所有對(duì)象的默認(rèn)版本,你可以自定義所有對(duì)象或者僅定義一個(gè)子集。如果你選擇正確的對(duì)象集,你應(yīng)該能夠只用少量的代碼創(chuàng)建你的動(dòng)畫。即使包含交互的動(dòng)畫,如果你利用UIKit提供的現(xiàn)有代碼,也可以輕松地實(shí)現(xiàn)。

轉(zhuǎn)場的代理

轉(zhuǎn)場代理是轉(zhuǎn)場動(dòng)畫和自定義presentations的起點(diǎn)。轉(zhuǎn)場代理是一個(gè)你定義的并遵守UIViewControllerTransitioningDelegate協(xié)議的對(duì)象。它的工作是為UIKit提供以下對(duì)象:

  1. 動(dòng)畫對(duì)象。動(dòng)畫對(duì)象是負(fù)責(zé)創(chuàng)建用于顯示或隱藏一個(gè)視圖控制器的視圖的動(dòng)畫。轉(zhuǎn)場代理可以提供用于presentingdismissing視圖控制器的單獨(dú)的動(dòng)畫對(duì)象。動(dòng)畫對(duì)象遵守UIViewControllerAnimatedTransitioning協(xié)議。
  2. 交互式動(dòng)畫對(duì)象。交互式動(dòng)畫對(duì)象使用觸摸事件或者手勢識(shí)別器來驅(qū)動(dòng)自定義動(dòng)畫的定時(shí)。交互式動(dòng)畫對(duì)象遵守UIViewControllerInteractiveTransitioning協(xié)議。創(chuàng)建交互式動(dòng)畫的最簡單方法是將UIPercentDrivenInteractiveTransition子類化,并向你的子類添加事件處理代碼。該類控制使用現(xiàn)有動(dòng)畫對(duì)象創(chuàng)建的動(dòng)畫的時(shí)間。如果你創(chuàng)建自己的交互式動(dòng)畫,你必須自己渲染動(dòng)畫的每個(gè)幀。
  3. 呈現(xiàn)的控制器(persentation controller)。在視圖控制器在屏幕上時(shí)呈現(xiàn)控制器管理著呈現(xiàn)風(fēng)格。系統(tǒng)提供了內(nèi)置呈現(xiàn)樣式的呈現(xiàn)控制器,你可以為你自己的呈現(xiàn)樣式提供自定義呈現(xiàn)控制器。有關(guān)創(chuàng)建自定義的呈現(xiàn)控制器的更多信息,請看Creating Custom Presentations.

給視圖控制器的transitioningDelegate賦值一個(gè)轉(zhuǎn)場代理對(duì)象,告訴UIKit你想要執(zhí)行自定義轉(zhuǎn)場或呈現(xiàn)。你的代理可以選擇它提供的哪些對(duì)象。如果你不提供動(dòng)畫對(duì)象,UIKit會(huì)在視圖控制器的modalTransitionStyle屬性中使用標(biāo)準(zhǔn)的轉(zhuǎn)場動(dòng)畫。

圖10-1顯示轉(zhuǎn)場代理和動(dòng)畫對(duì)象與被呈現(xiàn)視圖控制器的關(guān)系。presentation controller僅在視圖控制器的modalPresentationStyle的屬性設(shè)置為UIModalPresentationCustom時(shí)使用。

圖10-1

有關(guān)如何實(shí)現(xiàn)你的轉(zhuǎn)場代理的更多信息,請看Implement the Transitioning Delegate.有關(guān)轉(zhuǎn)場代理對(duì)象的方法的更多信息,請看UIViewControllerTransitioningDelegate Protocol Reference.

轉(zhuǎn)場動(dòng)畫序列

當(dāng)一個(gè)被呈現(xiàn)的視圖控制器的transitioningDelegate屬性包含一個(gè)有效的對(duì)象時(shí),UIKit會(huì)使用你提供的自定義動(dòng)畫對(duì)象呈現(xiàn)那個(gè)視圖控制器。在準(zhǔn)備呈現(xiàn)時(shí),UIKit會(huì)調(diào)用你的轉(zhuǎn)場代理的animationControllerForPresentedController:presentingController:sourceController:方法來獲取自定義動(dòng)畫對(duì)象。如果一個(gè)對(duì)象是有效的,UIKit會(huì)執(zhí)行下面的步驟:

  • 如果一個(gè)交互式動(dòng)畫對(duì)象是有效的,UIKit會(huì)調(diào)用轉(zhuǎn)場代理的interactionControllerForPresentation:方法。如果該方法返回nil,UIKit會(huì)執(zhí)行沒有用戶交互的動(dòng)畫。
  • UIKit會(huì)調(diào)用動(dòng)畫對(duì)象的transitionDuration:方法來獲取動(dòng)畫時(shí)長。
  • UIKit會(huì)調(diào)用恰當(dāng)?shù)姆椒▉黹_始動(dòng)畫:
    • 對(duì)于非交互式動(dòng)畫,UIKit會(huì)調(diào)用動(dòng)畫對(duì)象的animateTransition:方法
    • 對(duì)于交互式動(dòng)畫,UIKit會(huì)調(diào)用交互式動(dòng)畫對(duì)象的startInteractiveTransition:方法。
  • UIKit等待一個(gè)動(dòng)畫對(duì)象調(diào)用上下文轉(zhuǎn)場對(duì)象的completeTransition:方法。你的自定義動(dòng)畫對(duì)象在動(dòng)畫完成后調(diào)用這個(gè)方法,尤其是在動(dòng)畫的完成回調(diào)里。調(diào)用這個(gè)方法來結(jié)束轉(zhuǎn)場,并且讓UIKit知道它可以調(diào)用presentViewController:animated:completion的完成處理和調(diào)用動(dòng)畫對(duì)象自己的animationEnded:方法。

當(dāng)dismissing一個(gè)視圖控制器時(shí),UIKit調(diào)用你的轉(zhuǎn)場代理的animationControllerForDismissedController:方法并執(zhí)行下面的步驟:

  • 如果一個(gè)交互式動(dòng)畫對(duì)象時(shí)有效的,UIKit會(huì)調(diào)用轉(zhuǎn)場代理的interactionControllerForDismissal:方法。如果方法返回nil,UIKit會(huì)執(zhí)行沒有用戶交互的動(dòng)畫。
  • UIKit會(huì)調(diào)用動(dòng)畫對(duì)象的transitionDuration:方法來獲取動(dòng)畫時(shí)長。
  • UIKit會(huì)調(diào)用恰當(dāng)?shù)姆椒▉黹_始動(dòng)畫:
    • 對(duì)于非交互式動(dòng)畫,UIKit會(huì)調(diào)用動(dòng)畫對(duì)象的animateTransition:方法
    • 對(duì)于交互式動(dòng)畫,UIKit會(huì)調(diào)用交互式動(dòng)畫對(duì)象的startInteractiveTransition:方法。
  • UIKit等待一個(gè)動(dòng)畫對(duì)象調(diào)用上下文轉(zhuǎn)場對(duì)象的completeTransition:方法。你的自定義動(dòng)畫對(duì)象會(huì)在他的動(dòng)畫完成后調(diào)用這個(gè)方法,尤其是在動(dòng)畫的完成回調(diào)里。調(diào)用這個(gè)方法來結(jié)束轉(zhuǎn)場,并讓UIKit知道它可以調(diào)用presentViewController:animated:completion:方法的完成處理回調(diào)和調(diào)用動(dòng)畫對(duì)象自己的animationEnded:方法。

注意:在你的動(dòng)畫結(jié)束時(shí)調(diào)用completeTransition:方法是必須的。UIKit不會(huì)結(jié)束轉(zhuǎn)場過程,從而將控制權(quán)返回到你的應(yīng)用程序,直到你調(diào)用了該方法。

轉(zhuǎn)場上下文對(duì)象

在轉(zhuǎn)場動(dòng)畫開始前,UIKit會(huì)創(chuàng)建一個(gè)轉(zhuǎn)場上下文對(duì)象,并給它填充關(guān)于如何執(zhí)行動(dòng)畫的信息。轉(zhuǎn)場上下文兌現(xiàn)是你的代碼中重要的一部分。它實(shí)現(xiàn)了UIViewControllerContextTransitioning協(xié)議,并儲(chǔ)存著在轉(zhuǎn)場中視圖控制器和視圖相關(guān)的引用。它也儲(chǔ)存著一些信息,關(guān)于你應(yīng)該如何執(zhí)行轉(zhuǎn)場,包括動(dòng)畫是否是交互的。你的動(dòng)畫對(duì)象需要所有的這些信息來設(shè)置和執(zhí)行真實(shí)的動(dòng)畫。

注意:在設(shè)置自定義動(dòng)畫時(shí),總是使用轉(zhuǎn)場上下文對(duì)象中的對(duì)象和數(shù)據(jù)而不是使用你管理自己的緩存信息。轉(zhuǎn)場在多種條件下會(huì)發(fā)生,有一些可能會(huì)改變動(dòng)畫的參數(shù)。轉(zhuǎn)場上下文對(duì)象保證了你需要執(zhí)行動(dòng)畫的正確信息,而你的緩存信息可能會(huì)在你調(diào)用動(dòng)畫的方法時(shí)失效。

圖10-2顯示轉(zhuǎn)場上下文對(duì)象如何和其他對(duì)象交互。你的動(dòng)畫對(duì)象在它的animateTransition:方法中接受對(duì)象。你創(chuàng)建的動(dòng)畫應(yīng)該在提供的容器視圖中進(jìn)行。例如,當(dāng)正在呈現(xiàn)一個(gè)視圖控制器時(shí),添加它的視圖作為這個(gè)容器視圖的子視圖。這個(gè)容器視圖可能會(huì)是窗口或者一個(gè)有規(guī)律的視圖,但是它總是被配置來運(yùn)行你的動(dòng)畫。
圖:

圖10-2

有關(guān)轉(zhuǎn)場上下文對(duì)象的更多信息,請看UIViewControllerContextTransitioning Protocol Reference.

轉(zhuǎn)場協(xié)調(diào)器

對(duì)于內(nèi)置的轉(zhuǎn)場和你自定義的轉(zhuǎn)場,UIKit會(huì)創(chuàng)建一個(gè)轉(zhuǎn)場協(xié)調(diào)器對(duì)象來促進(jìn)任何你可能需要執(zhí)行的特別的動(dòng)畫。除了視圖控制器的presentationdismissal外,轉(zhuǎn)場會(huì)在界面發(fā)生旋轉(zhuǎn)或視圖控制器的frame改變時(shí)產(chǎn)生。所有這些轉(zhuǎn)場代表著視圖層級(jí)的改變。轉(zhuǎn)場協(xié)調(diào)器是一種方式來跟蹤這些變化,并同時(shí)使你的內(nèi)容動(dòng)畫。訪問轉(zhuǎn)場協(xié)調(diào)器,從受影響的視圖控制器的transitionCoordinator屬性中獲取該對(duì)象。轉(zhuǎn)場協(xié)調(diào)器只在轉(zhuǎn)場過程中存在。

圖10-3顯示轉(zhuǎn)場協(xié)調(diào)器與有關(guān)presentation的視圖控制器的關(guān)系。使用轉(zhuǎn)場協(xié)調(diào)器來獲取轉(zhuǎn)場的信息,并注冊要與轉(zhuǎn)場動(dòng)畫同時(shí)執(zhí)行的動(dòng)畫塊。轉(zhuǎn)場協(xié)調(diào)器對(duì)象遵守UIViewControllerTransitionCoordinatorContext協(xié)議,它提供定時(shí)信息,動(dòng)畫的當(dāng)前狀態(tài)信息,在轉(zhuǎn)場中涉及的視圖和視圖控制器。當(dāng)你的動(dòng)畫塊被執(zhí)行時(shí),它一樣會(huì)收到一個(gè)上下文對(duì)象帶有相同的信息。

圖10-3

有關(guān)轉(zhuǎn)場協(xié)調(diào)器對(duì)象的更多信息,請看UIViewControllerTransitionCoordinator Protocol Reference。有關(guān)你可以用來配置你的動(dòng)畫的上下文信息,請看UIViewControllerTransitionCoordinatorContext Protocol Reference.

使用自定義的動(dòng)畫呈現(xiàn)一個(gè)視圖控制器

使用自定義的動(dòng)畫來呈現(xiàn)一個(gè)視圖控制器,需要做以下你的視圖控制器的動(dòng)作方法:

  • 創(chuàng)建一個(gè)你想要呈現(xiàn)的視圖控制器
  • 創(chuàng)建你的自定義的轉(zhuǎn)場代理對(duì)象,并把它賦值給視圖控制器的transitioningDelegate屬性。你的轉(zhuǎn)場代理的方法應(yīng)該當(dāng)調(diào)用時(shí)創(chuàng)建和返回你的自定義動(dòng)畫對(duì)象。
  • 調(diào)用presentViewController:animated:completion:方法來呈現(xiàn)這個(gè)視圖控制器。

當(dāng)你調(diào)用presentViewController:animated:completion:方法時(shí),UIkit會(huì)啟動(dòng)呈現(xiàn)過程。Presentations在下一個(gè)運(yùn)行循環(huán)迭代期間開始并繼續(xù),直到你的自定義動(dòng)畫調(diào)用了completeTransition:方法。交互式轉(zhuǎn)場允許你在轉(zhuǎn)場正在進(jìn)行時(shí)處理觸摸事件,但非交互式轉(zhuǎn)場在由動(dòng)畫對(duì)象指定的持續(xù)時(shí)間內(nèi)運(yùn)行。

實(shí)現(xiàn)轉(zhuǎn)場代理

轉(zhuǎn)場代理的作用是用來創(chuàng)建和返回你的自定義對(duì)象。表10-1顯示了轉(zhuǎn)場方法的實(shí)現(xiàn)可以如此簡單。這個(gè)例子創(chuàng)建并返回了一個(gè)自定義動(dòng)畫對(duì)象。大多數(shù)實(shí)際工作都是由動(dòng)畫對(duì)象自己來處理。

//Listing 10-1Creating an animator object
- (id<UIViewControllerAnimatedTransitioning>)
    animationControllerForPresentedController:(UIViewController *)presented
                     presentingController:(UIViewController *)presenting
                         sourceController:(UIViewController *)source {
    MyAnimator* animator = [[MyAnimator alloc] init];
    return animator;
}

轉(zhuǎn)場代理的其它方法可以像上面清單上的方法一樣簡單。你也可以結(jié)合自定義的邏輯,根據(jù)你的應(yīng)用程序的當(dāng)前狀態(tài)返回不同的動(dòng)畫對(duì)象。有關(guān)轉(zhuǎn)場代理的方法的更多信息,請看UIViewControllerTransitioningDelegate Protocol Reference.

實(shí)現(xiàn)你的動(dòng)畫對(duì)象

一個(gè)動(dòng)畫對(duì)象是任何遵守了UIViewControllerAnimatedTransitioning協(xié)議的對(duì)象。動(dòng)畫對(duì)象創(chuàng)建在固定時(shí)間段內(nèi)執(zhí)行的動(dòng)畫。動(dòng)畫對(duì)象的關(guān)鍵是它的animateTransition:方法,你用來創(chuàng)建真實(shí)的動(dòng)畫。動(dòng)畫的過程大致分為以下幾個(gè)部分:

  • 獲取動(dòng)畫參數(shù)
  • 使用CoreAnimationUIView的動(dòng)畫方法創(chuàng)建動(dòng)畫
  • 清理并完成轉(zhuǎn)場
獲取動(dòng)畫參數(shù)

傳遞給你的animateTransition:方法的上下文轉(zhuǎn)場對(duì)象包含在執(zhí)行你的動(dòng)畫時(shí)使用的數(shù)據(jù)。在你可以從上下文轉(zhuǎn)場對(duì)象獲取更多最新數(shù)據(jù)信息時(shí),不要使用你自己的緩存信息或者從你的視圖控制器請求到的信息。Presentingdismissing視圖控制器有時(shí)候涉及到你的視圖控制器之外的對(duì)象。例如,一個(gè)自定義的呈現(xiàn)控制器可能會(huì)添加一個(gè)背景視圖作為呈現(xiàn)的一部分。上下文轉(zhuǎn)場對(duì)象考慮了額外的視圖和對(duì)象,并為您提供了動(dòng)畫的正確視圖。

  • 調(diào)用兩次viewControllerForKey:方法,以獲取轉(zhuǎn)場中涉及的”from”和”to”視圖控制器。不要假設(shè)你知道哪些視圖控制器參與了轉(zhuǎn)場。UIKit可能會(huì)在適應(yīng)新的特殊環(huán)境或響應(yīng)你的應(yīng)用程序請求時(shí)更換視圖控制器。
  • 為了動(dòng)畫調(diào)用contrainerView方法來獲取父視圖。給這個(gè)視圖添加關(guān)鍵的子視圖。例如,在呈現(xiàn)期間,給這個(gè)視圖添加被呈現(xiàn)的視圖控制器的視圖。
  • 調(diào)用viewForKey:方法來獲取要添加或刪除的視圖。視圖控制器的視圖在轉(zhuǎn)場過程中可能不是唯一的要被添加或被移除。presentation控制器可能插入視圖到視圖層級(jí)中,也必須被添加或移除。viewForKey:方法會(huì)返回包含所有你需要添加或移除的根視圖。
  • 調(diào)用finalFrameForViewController:方法可以獲取要添加或移除的視圖的最終的frame矩形。

上下文轉(zhuǎn)場對(duì)象使用”from”和”to”術(shù)語來標(biāo)識(shí)視圖控制器, 視圖,和轉(zhuǎn)場中涉及到的frame矩形。在轉(zhuǎn)場開始的時(shí)候”from”視圖控制器的視圖總是在當(dāng)前屏幕上,在轉(zhuǎn)場結(jié)束的時(shí)候”to”視圖控制器將會(huì)被看見。在圖10-4中你可以看到,在presentationdismissal時(shí)“from”和”to"視圖控制器交換了位置。

圖10-4

交換值使它更容易寫一個(gè)單個(gè)的動(dòng)畫來處理presentationsdismissals。當(dāng)你設(shè)計(jì)你的動(dòng)畫時(shí),你總是必須要做的是包含一個(gè)屬性來知道它的動(dòng)畫是presentation還是dismissal。兩者之間唯一需要的區(qū)別如下:

  • 對(duì)于presentation, 添加”to”視圖到容器視圖的層級(jí)。
  • 對(duì)于dismissal,從容器視圖的層級(jí)移除”from”視圖。
創(chuàng)建轉(zhuǎn)場動(dòng)畫

在典型的presentation期間,屬于被呈現(xiàn)的視圖控制器的視圖被動(dòng)畫化到位。其它的視圖可能作為你的presentation的一部分動(dòng)畫,但是你的動(dòng)畫的主要目標(biāo)總是被添加到視圖層級(jí)中的視圖。
當(dāng)動(dòng)畫主要視圖時(shí),你配置你的動(dòng)畫的基本動(dòng)作是相同的。你從轉(zhuǎn)場上下文獲取你需要的對(duì)象和數(shù)據(jù),并使用這些信息來創(chuàng)建你的真實(shí)的動(dòng)畫。

  • Presentation動(dòng)畫:
    • 使用viewControllerForKey:viewForKey:方法來獲取涉及到轉(zhuǎn)場中的視圖控制器和視圖。
    • 設(shè)置”to”視圖的開始位置。將任何其它屬性設(shè)置為其初始值。
    • 從轉(zhuǎn)場上下文的finalFrameForViewController:獲取”to”視圖的最終位置。
    • 把”to"視圖作為子視圖添加到容器視圖中。
    • 創(chuàng)建動(dòng)畫
      • 在你的動(dòng)畫塊中,將”to”視圖動(dòng)畫到它在容器視圖中的最終位置。將任何其它屬性設(shè)置為其最終值。
      • 在完成塊中,調(diào)用completeTransition:方法,并執(zhí)行其它的清理。
  • Dismissal動(dòng)畫:
    • 使用viewControllerForKey:viewForKey:方法來獲取涉及到轉(zhuǎn)場中的視圖控制器和視圖。
    • 計(jì)算”from”視圖的結(jié)束位置。屬于被呈現(xiàn)的視圖控制器的視圖開始消失。
    • 將”to"視圖作為子視圖添加到容器視圖中。
    • presentation期間,當(dāng)轉(zhuǎn)場完成時(shí)屬于呈現(xiàn)的視圖控制器的視圖被移除。結(jié)果,你必須在dismissal操作期間將那個(gè)視圖添加回容器中。
    • 創(chuàng)建動(dòng)畫
      • 在你的動(dòng)畫塊中,將”from”視圖動(dòng)畫到它在容器視圖中的最終位置。將任何其它屬性設(shè)置為其最終值。
      • 在完成塊中,將”from”視圖從你的視圖層級(jí)中移除并調(diào)用completeTransition:方法。根據(jù)需要執(zhí)行任何其它的清理。

圖10-5顯示了一個(gè)自定義的presentationdismissal轉(zhuǎn)場,動(dòng)畫它的對(duì)角視圖。在presentation期間,被呈現(xiàn)的視圖空屏幕開始并向?qū)蔷€向左上方動(dòng)畫直到它是可見的。在dismissal期間,視圖反轉(zhuǎn)方向,向右下方動(dòng)畫直到它再次離開屏幕。

圖10-5

列表10-2顯示你將如何實(shí)現(xiàn)圖10-5上顯示的轉(zhuǎn)場。在獲取到動(dòng)畫需要的對(duì)象后,animateTransition:方法計(jì)算被影響的視圖的frame矩形。在presentation期間,被呈現(xiàn)的視圖由“toView”表示。在dismissal期間,被消失的視圖由”fromView”表示。presenting屬性是動(dòng)畫對(duì)象自己的自定義屬性,在創(chuàng)建動(dòng)畫對(duì)象的時(shí)候?qū)⑥D(zhuǎn)場代理設(shè)置為合適的值。

//Listing 10-2Animations for implementing a diagonal presentation and dismissal    
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
// Get the set of relevant objects.
UIView *containerView = [transitionContext containerView];
UIViewController *fromVC = [transitionContext
        viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVC   = [transitionContext
        viewControllerForKey:UITransitionContextToViewControllerKey];

UIView *toView = [transitionContext viewForKey:UITransitionContextToViewKey];
UIView *fromView = [transitionContext viewForKey:UITransitionContextFromViewKey];

// Set up some variables for the animation.
CGRect containerFrame = containerView.frame;
CGRect toViewStartFrame = [transitionContext initialFrameForViewController:toVC];
CGRect toViewFinalFrame = [transitionContext finalFrameForViewController:toVC];
CGRect fromViewFinalFrame = [transitionContext finalFrameForViewController:fromVC];

// Set up the animation parameters.
if (self.presenting) {
    // Modify the frame of the presented view so that it starts
    // offscreen at the lower-right corner of the container.
    toViewStartFrame.origin.x = containerFrame.size.width;
    toViewStartFrame.origin.y = containerFrame.size.height;
}
else {
    // Modify the frame of the dismissed view so it ends in
    // the lower-right corner of the container view.
    fromViewFinalFrame = CGRectMake(containerFrame.size.width,
                                  containerFrame.size.height,
                                  toView.frame.size.width,
                                  toView.frame.size.height);
}

// Always add the "to" view to the container.
// And it doesn't hurt to set its start frame.
[containerView addSubview:toView];
toView.frame = toViewStartFrame;

// Animate using the animator's own duration value.
[UIView animateWithDuration:[self transitionDuration:transitionContext]
                 animations:^{
                     if (self.presenting) {
                         // Move the presented view into position.
                         [toView setFrame:toViewFinalFrame];
                     }
                     else {
                         // Move the dismissed view offscreen.
                         [fromView setFrame:fromViewFinalFrame];
                     }
                 }
                 completion:^(BOOL finished){
                     BOOL success = ![transitionContext transitionWasCancelled];

                     // After a failed presentation or successful dismissal, remove the view.
                     if ((self.presenting && !success) || (!self.presenting && success)) {
                         [toView removeFromSuperview];
                     }

                     // Notify UIKit that the transition has finished
                     [transitionContext completeTransition:success];
                 }];
 }
動(dòng)畫結(jié)束后清理

在轉(zhuǎn)場動(dòng)畫結(jié)束后,請務(wù)必調(diào)用completeTransition:方法。調(diào)用這個(gè)方法告訴UIKit轉(zhuǎn)場完成了,用戶可以開始使用被呈現(xiàn)的視圖控制器。調(diào)用這個(gè)方法也會(huì)引發(fā)其它完成處理程序的級(jí)聯(lián),包括一個(gè)來自于presentViewController:animated:completion:方法和動(dòng)畫對(duì)象自己的animationEnded:方法。
調(diào)用completeTransition:方法最好的地方是在你的動(dòng)畫塊的完成處理方法里。
因?yàn)檗D(zhuǎn)場能夠被取消,你應(yīng)該使用上下文對(duì)象的transitionWasCancelled方法的返回值來確定需要清理。當(dāng)一個(gè)presentation被取消時(shí),你的動(dòng)畫必須撤銷對(duì)視圖層級(jí)所做的任何修改。一個(gè)成功的dismissal需要相同的操作。

將交互式添加到你的轉(zhuǎn)場

最容易的方法使你的動(dòng)畫交互是使用UIPercentDrivenInteractiveTransition對(duì)象。UIPercentDrivenInteractiveTransition對(duì)象與你現(xiàn)有的動(dòng)畫對(duì)象配合使用來控制其動(dòng)畫時(shí)間。它使用你提供的完成百分比值。你必須要做的是編寫需要的事件處理的代碼來計(jì)算完成百分比值并新的事件達(dá)到時(shí)更新它。
你可以使用帶有子類或不帶有子類的UIPercentDrivenInteractiveTransition類。如果你子類化了,使用你的子類的init方法(或startInteractiveTransition:方法)來執(zhí)行一次創(chuàng)建你的事件處理代碼。之后,使用你的自定義的事件處理代碼來計(jì)算新的完成百分比值并調(diào)用updateInteractiveTransition:方法。當(dāng)你的代碼確定轉(zhuǎn)場應(yīng)該完成了,調(diào)用finishInteractiveTransition方法。
列表10-3顯示UIPrecentDrivenInteractiveTransition子類的startInteractiveTransition:方法的自定義實(shí)現(xiàn)。這個(gè)方法設(shè)置一個(gè)平移手勢識(shí)別器來跟蹤觸摸事件并將該手勢識(shí)別器安裝在動(dòng)畫的容器視圖上。它還保存轉(zhuǎn)場上下文的引用以供以后使用。

Listing 10-3Configuring a percent-driven interactive animator
- (void)startInteractiveTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
   // Always call super first.
   [super startInteractiveTransition:transitionContext];

   // Save the transition context for future reference.
   self.contextData = transitionContext;

   // Create a pan gesture recognizer to monitor events.
   self.panGesture = [[UIPanGestureRecognizer alloc]
                    initWithTarget:self action:@selector(handleSwipeUpdate:)];
   self.panGesture.maximumNumberOfTouches = 1;

   // Add the gesture recognizer to the container view.
   UIView* container = [transitionContext containerView];
   [container addGestureRecognizer:self.panGesture];
}

在任何新的事件達(dá)到時(shí)手勢識(shí)別器會(huì)調(diào)用它的動(dòng)作方法。你的動(dòng)作方法的實(shí)現(xiàn)可以使用手勢識(shí)別器的狀態(tài)信息來確定手勢是否成功,失敗或一直在進(jìn)行。同時(shí),你可以使用最新的觸摸事件信息來計(jì)算手勢的新的百分比值。
列表10-4顯示由列表10-3中配置的平移手勢識(shí)別器調(diào)用的方法。當(dāng)新的事件到達(dá)時(shí),此方法使用垂直行程距離來計(jì)算動(dòng)畫的完成百分比值。當(dāng)手勢結(jié)束時(shí),該方法結(jié)束轉(zhuǎn)場。

// Listing 10-4Using events to update the animation progress
-(void)handleSwipeUpdate:(UIGestureRecognizer )gestureRecognizer {
UIView
container = [self.contextData containerView];

  if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
      // Reset the translation value at the beginning of the gesture.
      [self.panGesture setTranslation:CGPointMake(0, 0) inView:container];
  }
  else if (gestureRecognizer.state == UIGestureRecognizerStateChanged) {
      // Get the current translation value.
      CGPoint translation = [self.panGesture translationInView:container];

      // Compute how far the gesture has travelled vertically,
      //  relative to the height of the container view.
      CGFloat percentage = fabs(translation.y / CGRectGetHeight(container.bounds));

      // Use the translation value to update the interactive animator.
      [self updateInteractiveTransition:percentage];
  }
  else if (gestureRecognizer.state >= UIGestureRecognizerStateEnded) {
      // Finish the transition and remove the gesture recognizer.
      [self finishInteractiveTransition];
      [[self.contextData containerView] removeGestureRecognizer:self.panGesture];
  }
}

注意:你計(jì)算的值表示動(dòng)畫的整個(gè)長度的完成百分比。對(duì)于交互式動(dòng)畫,你可能想要避免效應(yīng),例如動(dòng)畫本身的初始速度、阻尼值和非線性完成曲線。這種效應(yīng)傾向于將事件的觸摸位置與任何下層視圖的移動(dòng)分離。

創(chuàng)建與轉(zhuǎn)場一起運(yùn)行的動(dòng)畫

涉及轉(zhuǎn)場的視圖控制器可以在任何presentation或轉(zhuǎn)場動(dòng)畫之上執(zhí)行附加動(dòng)畫。例如,被呈現(xiàn)的視圖控制器可能在轉(zhuǎn)場期間動(dòng)畫它自己的視圖層級(jí),并在轉(zhuǎn)場出現(xiàn)時(shí)添加移動(dòng)效果或其它視覺反饋。任何對(duì)象能夠創(chuàng)建動(dòng)畫,只要它能夠訪問被呈現(xiàn)或呈現(xiàn)的視圖控制器的transitionCoordinator屬性。轉(zhuǎn)場協(xié)調(diào)器屬性只在轉(zhuǎn)場正在進(jìn)行時(shí)存在。
為了創(chuàng)建動(dòng)畫,調(diào)用轉(zhuǎn)場協(xié)調(diào)器的animateAlongsideTransition:completion:animateAlongsideTransitionInView:animation:completion:方法。這個(gè)你提供的塊被存儲(chǔ)直到轉(zhuǎn)場動(dòng)畫開始,此時(shí)它們與其余的動(dòng)畫一起執(zhí)行。

使用Presentation控制器與你的動(dòng)畫

對(duì)于自定義presentation,你可以提供你自己的presentation控制器來給被呈現(xiàn)的視圖控制器一個(gè)自定義的外觀。Presentation控制器管理著視圖控制器和其內(nèi)容分離的任何自定義的chrome.例如,位于視圖控制器視圖的后面的調(diào)光視圖將由presentation控制器管理。事實(shí)上它沒有管理一個(gè)特殊的視圖控制器的視圖意味著你可以在你的應(yīng)用程序中使用相同的presentation控制器與任何視圖控制器。

你提供一個(gè)自定義的presentation控制器來自于被呈現(xiàn)視圖控制器的轉(zhuǎn)場代理。(視圖控制器的modalTransitionStyle屬性必須設(shè)置為UIModalPresentationCustom) presentation控制器與任何動(dòng)畫對(duì)象并行操作。由于動(dòng)畫對(duì)象將視圖控制器的視圖動(dòng)畫到位置,presentation控制器會(huì)將任何附加視圖動(dòng)畫到位置。轉(zhuǎn)場結(jié)束時(shí),presentation控制器有機(jī)會(huì)對(duì)視圖層級(jí)執(zhí)行任何最終調(diào)整。
關(guān)于如何創(chuàng)建一個(gè)自定義的presentation控制器的更多信息,請看Creating Custom Presentations

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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