IOS 抽屉效果

原创Blog,转载请注明出处

blog.csdn.net/hello_hwc

先看看Demo效果

视频链接如下

http://v.youku.com/v_show/id_XODc1OTQwODQ0.html

实现过程如下

1 新建一个基于单视图的工程。拖入两个ViewController,为了区分,在大纲中改为firstViewController 和 SecondViewController。沿着图中红线control+拖拽,在弹出的窗口中选择Show

技术分享


2 选择Segue,为其添加Identifier为:PushSegue
技术分享

3 为了区分,分别为两个ViewController设置不同的backgroundColor
技术分享

4 拖入一个ImageView到FirstViewController中,然后接下来的几幅图时为ImageView设置AutoLayout
设置居中
技术分享
保证长宽不变
技术分享
然后,update Frame让ImageView在正确的位置,然后为ImageView选择图片
技术分享

5 然后拖入一个Object到NavigationController中
技术分享
6 创建一个Cocoa Class文件,继承自NSObject,命名为NavigationControllerDelegate,让其遵循UINavigationControllerDelegate
@interface NavigationControllerDelegate : NSObject<UINavigationControllerDelegate>

7让storyboard上的NavigationController的代理设置为拖入的对象,方式:大纲中右键NavigationController,然后把代理拖拽到Object上
技术分享

8 然后为NavigationController设置一个Outlet
技术分享
9 接下来就是代码的过程了,完整的代码如下

NavigationControllerDelegate.h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface NavigationControllerDelegate : NSObject<UINavigationControllerDelegate>

@end

NavigationControllerDelegate.m

#import "NavigationControllerDelegate.h"
#import "Animator.h"

@interface NavigationControllerDelegate()<UIGestureRecognizerDelegate>

@property (strong,nonatomic)UIPercentDrivenInteractiveTransition * interactivcTransition;
@property (weak, nonatomic) IBOutlet UINavigationController *nav;
@property (strong,nonatomic) UIPanGestureRecognizer * pangesture;
@end

@implementation NavigationControllerDelegate
//添加手势
-(void)awakeFromNib{
    self.pangesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(paned:)];
    [self.nav.view addGestureRecognizer:self.pangesture];
}
//响应手势
- (void)paned:(UIPanGestureRecognizer *)sender {
    if (self.nav == nil){
        return;
    }
    CGPoint translation;
    switch (sender.state) {
        case UIGestureRecognizerStateBegan:
        {
            _interactivcTransition = [[UIPercentDrivenInteractiveTransition alloc] init];
            if (self.nav.viewControllers.count > 1) {
                [self.nav popViewControllerAnimated:YES];
            }
            else{
                [self.nav.topViewController performSegueWithIdentifier:@"PushSegue" sender:nil];
            }
        }
            break;
        case UIGestureRecognizerStateChanged:
            translation = [sender translationInView:self.nav.view];
            if (self.nav.viewControllers.count > 1 && translation.x > 0) {
                CGFloat completionProgress = translation.x/CGRectGetWidth(self.nav.view.frame);
                [self.interactivcTransition updateInteractiveTransition:completionProgress];
            }
            if (self.nav.viewControllers.count == 1 && translation.x < 0) {
                CGFloat completionProgress = -translation.x/CGRectGetWidth(self.nav.view.frame);
                [self.interactivcTransition updateInteractiveTransition:completionProgress];
            }
            break;
        case UIGestureRecognizerStateEnded:
            if (self.nav.viewControllers.count >1 && [sender velocityInView:self.nav.view].x>0) {
                [self.interactivcTransition finishInteractiveTransition];

            }else if(self.nav.viewControllers.count <= 1 && [sender velocityInView:self.nav.view].x<0){
                [self.interactivcTransition finishInteractiveTransition];
            }else{
                [self.interactivcTransition cancelInteractiveTransition];
            }
            break;
        case UIGestureRecognizerStateCancelled:
            [self.interactivcTransition cancelInteractiveTransition];
            break;
        default:
            [self.interactivcTransition cancelInteractiveTransition];
            self.interactivcTransition = nil;
            break;
    }
}
//NavigationController代理-决定了动画交互过程由哪个对象控制
- (id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
                          interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController{
    return self.interactivcTransition;
    
}
//NavigationController代理-决定了如何呈现动画
-(id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                 animationControllerForOperation:(UINavigationControllerOperation)operation
                                              fromViewController:(UIViewController *)fromVC
                                                toViewController:(UIViewController *)toVC
{
    return [[Animator alloc] init];
}

@end

//  Animator.h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface Animator : NSObject <UIViewControllerAnimatedTransitioning>

@end

//  Animator.m

//
//  Animator.m
//  HwcFoundationExample
//
//  Created by huangwenchen on 15/1/20.
//  Copyright (c) 2015年 huangwenchen. All rights reserved.
//


#import "Animator.h"

@implementation Animator
//动画时间
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext
{
    return 0.8;
}
//动画的过程
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
    UIViewController* fromviewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UINavigationController * nav = toViewController.navigationController;
    CGRect originFrame = toViewController.view.frame;
    CGRect offSetFrame = CGRectOffset(originFrame,-CGRectGetWidth(originFrame), 0);
    if (nav.viewControllers.count > 1) {
        [[transitionContext containerView] addSubview:toViewController.view];
        toViewController.view.frame = offSetFrame;
        [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
            toViewController.view.frame = originFrame;
        } completion:^(BOOL finished) {
            [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
        }];

    }else
    {
        [[transitionContext containerView] insertSubview:toViewController.view belowSubview:fromviewController.view];
        fromviewController.view.frame = originFrame;
        [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
            fromviewController.view.frame = offSetFrame;
        } completion:^(BOOL finished) {
            [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
            
        }];

    }
}
@end

第二部分
原理:这里我把抽屉的过程理解为两个ViewController的切换动画。那么,切换动画的组成要素有以下几部分

(1)动画控制器 (Animation Controllers) 遵从 UIViewControllerAnimatedTransitioning 协议,并且负责实际执行动画。
(2)交互控制器 (Interaction Controllers) 通过遵从 UIViewControllerInteractiveTransitioning 协议来控制可交互式的转场。
(3)转场代理 (Transitioning Delegates) 根据不同的转场类型方便的提供需要的动画控制器和交互控制器。
(4)转场上下文 (Transitioning Contexts) 定义了转场时需要的元数据,比如在转场过程中所参与的视图控制器和视图的相关属性。 转场上下文对象遵从 UIViewControllerContextTransitioning 协议,并且这是由系统负责生成和提供的。
(5)转场协调器(Transition Coordinators) 可以在运行转场动画时,并行的运行其他动画。 转场协调器遵从 UIViewControllerTransitionCoordinator 协议。



采用UINavigationController的话,我们只需要考虑动画控制器和交互控制器就可以了。

动画交互器由UIPercentDrivenInteractiveTransition提供

动画控制器由自定义一个类Animator,遵循UIViewControllerAnimatedTransitioning来提供,这个协议有两个必须实现的函数,就是代码中的两个函数。

这么做的好处就是动画本身的过程和ViewController解耦

BTY:demo仍然有些不完善的地方,等有时间了我再优化下

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。