在iOS7之前,View Controller的切換主要有4種:
- Push/Pop,NavigationViewController
- Present and dismis Modal
- UITabBarController
- addChildViewController(一般用于自定義的繼承于 UIViewController 的容器子類)
iOS5,調用- (void)transitionFromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion NS_AVAILABLE_IOS(5_0);
(1)前面3種方法這里就不多說了,很常見的系統方法.至于第四種,我在前面文章-剖析網易標簽欄的效果中已經做了闡述,但是它提供的容器轉場動畫只可以實現一些簡單的UIView動畫,但是難以重用,耦合高.
(2)關鍵的API:
A.動畫控制器 (Animation Controllers) 遵從 UIViewControllerAnimatedTransitioning 協議,并且負責實際執行動畫。
B.交互控制器 (Interaction Controllers) 通過遵從 UIViewControllerInteractiveTransitioning 協議來控制可交互式的轉場。
C.轉場代理 (Transitioning Delegates) 根據不同的轉場類型方便的提供需要的動畫控制器和交互控制器。
其中UINavigationControllerDelegate delegate 中新增了2個方法給NavigationController
UIViewControllerTransitioningDelegate 新增transitioningDelegate 給Modal的Present和Dismis
復制代碼 代碼如下:
UITabBarControllerDelegate delegate
- (id <UIViewControllerInteractiveTransitioning>)tabBarController:(UITabBarController *)tabBarController
interactionControllerForAnimationController: (id <UIViewControllerAnimatedTransitioning>)animationController NS_AVAILABLE_IOS(7_0);
- (id <UIViewControllerAnimatedTransitioning>)tabBarController:(UITabBarController *)tabBarController
animationControllerForTransitionFromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC NS_AVAILABLE_IOS(7_0);
D.轉場上下文 (Transitioning Contexts) 定義了轉場時需要的元數據,比如在轉場過程中所參與的視圖控制器和視圖的相關屬性。 轉場上下文對象遵從 UIViewControllerContextTransitioning 協議,并且這是由系統負責生成和提供的。
E.轉場協調器(Transition Coordinators) 可以在運行轉場動畫時,并行的運行其他動畫。 轉場協調器遵從 UIViewControllerTransitionCoordinator 協議。
(3)新的API主要提供了2種VC切換的方式:
A.非交互式切換,即定義一種從一個VC到另一個VC的動畫效果,切換的時候自動播放,
B.交互式切換,這種方式同樣需要定義動畫效果,只是這個動畫效果會根據跟隨交互式手勢來切換VC并同時播放動畫效果。iOS7提供了一個默認的基于百分比的動畫實現 UIPercentDrivenInteractiveTransition,而且根據WWDC的說明,最簡單的實現交互式動畫的方法就是通過繼承 UIPercentDrivenInteractiveTransition。蘋果給我們開發者提供的是都是協議接口,所以我們能夠很好的單獨提出來寫成一個個類,在里面實現我們各種自定義效果.
(4)來看看實現UIViewControllerAnimatedTransitioning的自定義動畫類
復制代碼 代碼如下:
/**
* 自定義的動畫類
* 實現協議------>@protocol UIViewControllerAnimatedTransitioning
* 這個接口負責切換的具體內容,也即“切換中應該發生什么”
*/
@interface MTHCustomAnimator : NSObject <UIViewControllerAnimatedTransitioning>
@end
@implementation MTHCustomAnimator
// 系統給出一個切換上下文,我們根據上下文環境返回這個切換所需要的花費時間
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
return 1.0;
}
// 完成容器轉場動畫的主要方法,我們對于切換時的UIView的設置和動畫都在這個方法中完成
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
// 可以看做為destination ViewController
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
// 可以看做為source ViewController
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
// 添加toView到容器上
// 如果是XCode6 就可以用這段
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
{
// iOS8 SDK 新API
UIView *toView = [transitionContext viewForKey:UITransitionContextToViewKey];
//UIView *fromView = [transitionContext viewForKey:UITransitionContextFromViewKey];
[[transitionContext containerView] addSubview:toView];
}else{
// 添加toView到容器上
[[transitionContext containerView] addSubview:toViewController.view];
}
// 如果是XCode5 就是用這段
[[transitionContext containerView] addSubview:toViewController.view];
toViewController.view.alpha = 0.0;
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
// 動畫效果有很多,這里就展示個左偏移
fromViewController.view.transform = CGAffineTransformMakeTranslation(-320, 0);
toViewController.view.alpha = 1.0;
} completion:^(BOOL finished) {
fromViewController.view.transform = CGAffineTransformIdentity;
// 聲明過渡結束-->記住,一定別忘了在過渡結束時調用 completeTransition: 這個方法
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}
PS:從協議中兩個方法可以看出,上面兩個必須實現的方法需要一個轉場上下文參數,這是一個遵從UIViewControllerContextTransitioning 協議的對象。通常情況下,當我們使用系統的類時,系統框架為我們提供的轉場代理(Transitioning Delegates),為我們創建了轉場上下文對象,并把它傳遞給動畫控制器。
復制代碼 代碼如下:
// MainViewController
@interface MTHMainViewController () <UINavigationControllerDelegate,UIViewControllerTransitioningDelegate>
@property (nonatomic,strong) MTHCustomAnimator *customAnimator;
@property (nonatomic,strong) PDTransitionAnimator *minToMaxAnimator;
@property (nonatomic,strong) MTHNextViewController *nextVC;
// 交互控制器 (Interaction Controllers) 通過遵從 UIViewControllerInteractiveTransitioning 協議來控制可交互式的轉場。
@property (strong, nonatomic) UIPercentDrivenInteractiveTransition* interactionController;
@end
@implementation MTHMainViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.navigationItem.title = @"Demo";
self.view.backgroundColor = [UIColor yellowColor];
// 設置代理
self.navigationController.delegate = self;
// 設置轉場動畫
self.customAnimator = [[MTHCustomAnimator alloc] init];
self.minToMaxAnimator = [PDTransitionAnimator new];
self.nextVC = [[MTHNextViewController alloc] init];
// Present的代理和自定義設置
_nextVC.transitioningDelegate = self;
_nextVC.modalPresentationStyle = UIModalPresentationCustom; (貌似有BUG)換成modalTransitionStyle = UIModalPresentationCustom
// Push
UIButton *pushButton = [UIButton buttonWithType:UIButtonTypeSystem];
pushButton.frame = CGRectMake(140, 200, 40, 40);
[pushButton setTitle:@"Push" forState:UIControlStateNormal];
[pushButton addTarget:self action:@selector(push) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:pushButton];
// Present
UIButton *modalButton = [UIButton buttonWithType:UIButtonTypeSystem];
modalButton.frame = CGRectMake(265, 500, 50, 50);
[modalButton setTitle:@"Modal" forState:UIControlStateNormal];
[modalButton addTarget:self action:@selector(modal) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:modalButton];
// 實現交互操作的手勢
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(didClickPanGestureRecognizer:)];
[self.navigationController.view addGestureRecognizer:panRecognizer];
}
- (void)push
{
[self.navigationController pushViewController:_nextVC animated:YES];
}
- (void)modal
{
[self presentViewController:_nextVC animated:YES completion:nil];
}
#pragma mark - UINavigationControllerDelegate iOS7新增的2個方法
// 動畫特效
- (id<UIViewControllerAnimatedTransitioning>) navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
{
/**
* typedef NS_ENUM(NSInteger, UINavigationControllerOperation) {
* UINavigationControllerOperationNone,
* UINavigationControllerOperationPush,
* UINavigationControllerOperationPop,
* };
*/
if (operation == UINavigationControllerOperationPush) {
return self.customAnimator;
}else{
return nil;
}
}
// 交互
- (id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController*)navigationController interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>)animationController
{
/**
* 在非交互式動畫效果中,該方法返回 nil
* 交互式轉場,自我理解意思是,用戶能通過自己的動作來(常見:手勢)控制,不同于系統缺省給定的push或者pop(非交互式)
*/
return _interactionController;
}
#pragma mark - Transitioning Delegate (Modal)
// 前2個用于動畫
-(id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
{
self.minToMaxAnimator.animationType = AnimationTypePresent;
return _minToMaxAnimator;
}
-(id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
{
self.minToMaxAnimator.animationType = AnimationTypeDismiss;
return _minToMaxAnimator;
}
// 后2個用于交互
- (id <UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id <UIViewControllerAnimatedTransitioning>)animator
{
return _interactionController;
}
- (id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id <UIViewControllerAnimatedTransitioning>)animator
{
return nil;
}
以上實現的是非交互的轉場,指的是完全按照系統指定的切換機制,用戶無法中途取消或者控制進度切換.那怎么來實現交互轉場呢:
UIPercentDrivenInteractiveTransition實現了UIViewControllerInteractiveTransitioning接口的類,,可以用一個百分比來控制交互式切換的過程。我們在手勢識別中只需要告訴這個類的實例當前的狀態百分比如何,系統便根據這個百分比和我們之前設定的遷移方式為我們計算當前應該的UI渲染,十分方便。具體的幾個重要方法:
-(void)updateInteractiveTransition:(CGFloat)percentComplete 更新百分比,一般通過手勢識別的長度之類的來計算一個值,然后進行更新。之后的例子里會看到詳細的用法
-(void)cancelInteractiveTransition 報告交互取消,返回切換前的狀態
主站蜘蛛池模板:
宜都市|
贵溪市|
石嘴山市|
镇宁|
旬邑县|
新蔡县|
滨州市|
门头沟区|
开江县|
榆树市|
广东省|
合山市|
九龙坡区|
都兰县|
屯门区|
鄂尔多斯市|
吕梁市|
运城市|
高密市|
文登市|
岗巴县|
西吉县|
伊通|
万年县|
汾西县|
札达县|
额敏县|
巍山|
新巴尔虎右旗|
吕梁市|
南皮县|
许昌市|
景洪市|
河西区|
楚雄市|
鄂伦春自治旗|
七台河市|
尼勒克县|
湘潭市|
台北市|
房产|