iOS开发自定义转场动画

1、转场动画

  iOS7之后开发者可以自定义界面切换的转场动画,就是在模态弹出(present、dismiss),Navigation的(push、pop),TabBar的系统切换效果之外自定义切换动画!

  模态弹出自定义出push、pop效果,可以侧滑:

2、实现步骤

  2.1、自定义转场动画

    1》创建自定义文件

@interface CustomTransform : NSObject<UIViewControllerAnimatedTransitioning>

    2》实现UIViewControllerAnimatedTransitioning方法

//设置转场时间
- (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext;
//设置转场效果
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext;

    .m相关类说明:

//表示转场动画上下文
UIViewControllerContextTransitioning
//当前控制器fromVC和目标控制器toVC
//vc1-->present-->vc2: fromVC是vc1,toVC是vc2
//vc2-->dismiss-->vc1: fromVC是vc2,toVC是vc1
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
//对应控制器的view视图
UIView *fromView =[transitionContext viewForKey:UITransitionContextFromViewKey];
UIView *toView =[transitionContext viewForKey:UITransitionContextToViewKey];

//presentingViewController,presentedViewController
vc1-->present-->vc2,vc1.presentedViewController 就是vc2;vc2.presentingViewController 就是vc1。

//更新动画进度
- (void)updateInteractiveTransition:(CGFloat)percentComplete;
//转场结束
- (void)finishInteractiveTransition;
//转场取消
- (void)cancelInteractiveTransition;

    自定义文件:

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

typedef NS_ENUM(NSInteger, PresentType){
    PresentTypePresent,
    PresentTypeDismiss
};

@interface CustomTransform : NSObject<UIViewControllerAnimatedTransitioning>

+ (instancetype)makeWithTransitionType:(PresentType)type;
- (instancetype)initWithTransitionType:(PresentType)type;


@end
.h文件
#import "CustomTransform.h"

@interface CustomTransform()

@property(nonatomic, assign)PresentType type;
@property(nonatomic, strong)UIView *containerView;
@end

@implementation CustomTransform
+ (instancetype)makeWithTransitionType:(PresentType)type
{
    return [[self alloc] initWithTransitionType:type];
}

- (instancetype)initWithTransitionType:(PresentType)type
{
    if (self == [super init]) {
        _type = type;
    }
    return self;
}

- (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext
{
    return .5;
}


- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext
{
    switch (_type) {
        case PresentTypePresent:
            [self presentTransform:transitionContext];
            break;
        case PresentTypeDismiss:
            [self dismissTransform:transitionContext];
            break;
        default:
            break;
    }
    
}

- (void)presentTransform:(id<UIViewControllerContextTransitioning>)transitionContext
{
    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    self.containerView = [transitionContext containerView];
    
    UIView *fromView =[transitionContext viewForKey:UITransitionContextFromViewKey];
    UIView *toView =[transitionContext viewForKey:UITransitionContextToViewKey];
    [self.containerView addSubview:toView];
    CGRect visibleFrame = [transitionContext initialFrameForViewController:fromVC];
    CGRect rightHiddenFrame = CGRectMake( CGRectGetWidth(visibleFrame), 0,CGRectGetWidth(visibleFrame),CGRectGetHeight(visibleFrame));
    CGRect leftHiddenFrame =CGRectMake(- CGRectGetWidth(visibleFrame), 0, CGRectGetWidth(visibleFrame), CGRectGetHeight(visibleFrame));
    fromView.frame = visibleFrame;
    toView.frame = rightHiddenFrame;
    fromView.layer.masksToBounds = toView.layer.masksToBounds = YES;
    [self.containerView insertSubview:toView atIndex:0];
    [UIView animateWithDuration:.5
                     animations:^{
                         fromView.frame = leftHiddenFrame;
                         toView.frame = visibleFrame;
                     }
                     completion:^(BOOL finished) {
                         if ([transitionContext transitionWasCancelled]) {
                             [toView removeFromSuperview];
                         }
                         [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
                     }];
    
}

- (void)dismissTransform:(id<UIViewControllerContextTransitioning>)transitionContext
{

    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    self.containerView = [transitionContext containerView];
    
    UIView *fromView =[transitionContext viewForKey:UITransitionContextFromViewKey];
    UIView *toView =[transitionContext viewForKey:UITransitionContextToViewKey];
    [self.containerView addSubview:toView];
    CGRect visibleFrame = [transitionContext initialFrameForViewController:fromVC];
    CGRect rightHiddenFrame = CGRectMake( CGRectGetWidth(visibleFrame), 0,CGRectGetWidth(visibleFrame),CGRectGetHeight(visibleFrame));
    CGRect leftHiddenFrame =CGRectMake(- CGRectGetWidth(visibleFrame), 0, CGRectGetWidth(visibleFrame), CGRectGetHeight(visibleFrame));
    fromView.frame = visibleFrame;
    toView.frame = leftHiddenFrame;
    fromView.layer.masksToBounds = toView.layer.masksToBounds = YES;
    [UIView animateWithDuration:.5
                     animations:^{
                         fromView.frame = rightHiddenFrame;
                         toView.frame = visibleFrame;
                     }
                     completion:^(BOOL finished) {
                         if ([transitionContext transitionWasCancelled]) {
                             [toView removeFromSuperview];
                         }
                         [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
                     }];
}

@end
.m文件

  2.2、自定义交互手势

    1》创建自定义文件

@interface CustonInteractive : UIPercentDrivenInteractiveTransition

    因为UIPercentDrivenInteractiveTransition : NSObject <UIViewControllerInteractiveTransitioning>,所以自定义时继承遵循UIViewControllerInteractiveTransitioning协议的UIPercentDrivenInteractiveTransition子类!

    2》相关文件:

#import <UIKit/UIKit.h>

@interface CustonInteractive : UIPercentDrivenInteractiveTransition

@property (nonatomic, assign) BOOL interacting;

- (void)wireToViewController:(UIViewController*)viewController;

@end
.h
#import "CustonInteractive.h"


@interface CustonInteractive()
@property (nonatomic, strong) UIViewController *presentingVC;

@end

@implementation CustonInteractive
-(void)wireToViewController:(UIViewController *)viewController
{
    self.presentingVC = viewController;
    [self prepareGestureRecognizerInView:viewController.view];
}

- (void)prepareGestureRecognizerInView:(UIView*)view {
    UIPanGestureRecognizer *gesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];
    [view addGestureRecognizer:gesture];
}
- (void)handleGesture:(UIPanGestureRecognizer *)gestureRecognizer {
    CGFloat progress = [gestureRecognizer translationInView:gestureRecognizer.view.superview].x / (self.presentingVC.view.bounds.size.width * 1.0);
    progress = MIN(1.0, MAX(0.0, progress));//把这个百分比限制在0~1之间
    NSLog(@"===%lf",progress);
    if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
        self.interacting = YES;
        [self.presentingVC dismissViewControllerAnimated:YES completion:nil];
    }
    else if (gestureRecognizer.state == UIGestureRecognizerStateChanged){
        if (self.interacting) {
            [self updateInteractiveTransition:progress];
        }
    }else if (gestureRecognizer.state == UIGestureRecognizerStateCancelled||gestureRecognizer.state==UIGestureRecognizerStateEnded){
        if (self.interacting) {
            if (progress>0.5) {
                [self finishInteractiveTransition];
            }else{
                [self cancelInteractiveTransition];
            }
            self.interacting = NO;
        }
    }
}

@end
.m

  2.3、使用自定义转场动画

    1》设置代理(以模态弹出为例)设置目标控制器的 transitioningDelegate

- (IBAction)present:(id)sender {
    PresentedViewController *vc = [[PresentedViewController alloc] init];
    vc.transitioningDelegate = self;
    [_transitionController wireToViewController:vc];
    [self presentViewController:vc animated:YES completion:nil];
}

     附加:Navigation和TabBar代理设置(self.delegate = self)

    2》实现UIViewControllerTransitioningDelegate代理方法

1 //设置弹出时动画协议
2 - (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source;
3 //设置消失时动画协议
4 - (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed;
5 //设置消失时手势协议
6 - (nullable id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id <UIViewControllerAnimatedTransitioning>)animator;

    vc1的.m文件:

 1 #import "PresentingViewController.h"
 2 #import "CustomTransform.h"
 3 #import "CustonInteractive.h"
 4 #import "PresentedViewController.h"
 5 
 6 
 7 #import "SecondTransform.h"
 8 #import "SecondInteractive.h"
 9 @interface PresentingViewController ()<UIViewControllerTransitioningDelegate,UINavigationControllerDelegate,UITabBarControllerDelegate>{
10     SecondTransform *_presentAnimation;
11     SecondInteractive *_transitionController;
12 }
13 
14 @end
15 
16 @implementation PresentingViewController
17 
18 - (void)viewDidLoad {
19     [super viewDidLoad];
20     _presentAnimation = [SecondTransform new];
21     _transitionController = [SecondInteractive new];
22     // Do any additional setup after loading the view from its nib.
23 }
24 - (IBAction)present:(id)sender {
25     PresentedViewController *vc = [[PresentedViewController alloc] init];
26     vc.transitioningDelegate = self;
27     [_transitionController wireToViewController:vc];
28     [self presentViewController:vc animated:YES completion:nil];
29 }
30 - (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
31 {
32     return _presentAnimation;
33 }
34 
35 - (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
36 {
37     return [SecondTransform makeWithTransitionType:PresentTransformAnimationTypeDismissed];
38 }
39 
40 -(id<UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id<UIViewControllerAnimatedTransitioning>)animator {
41     return _transitionController.isInterraction ? _transitionController : nil;
42 }
43 @end
.m

     Navigation和TabBar的代理方法:

#pragma mark---UINavigationControllerDelegate
/*
- (nullable id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
                                   interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController NS_AVAILABLE_IOS(7_0);

- (nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                            animationControllerForOperation:(UINavigationControllerOperation)operation
                                                         fromViewController:(UIViewController *)fromVC
                                                           toViewController:(UIViewController *)toVC  NS_AVAILABLE_IOS(7_0);
*/

#pragma mark-UITabBarControllerDelegate
/*
- (nullable id <UIViewControllerInteractiveTransitioning>)tabBarController:(UITabBarController *)tabBarController
                               interactionControllerForAnimationController: (id <UIViewControllerAnimatedTransitioning>)animationController NS_AVAILABLE_IOS(7_0);

- (nullable id <UIViewControllerAnimatedTransitioning>)tabBarController:(UITabBarController *)tabBarController
                     animationControllerForTransitionFromViewController:(UIViewController *)fromVC
                                                       toViewController:(UIViewController *)toVC  NS_AVAILABLE_IOS(7_0);
*/
Navigation和TabBar的delegate

 

posted @ 2018-04-16 17:12  ForeverGuard  阅读(2048)  评论(0编辑  收藏  举报