自定义UIViewController的过渡效果

原创
2014/11/06 21:25
阅读数 38
在iOS应用中,UIViewController是主要的组成部分,controllers可以通过navigation controllers, tab bar controllers, and modally这几种方式呈现。在ios7发布之前,控制器的展示效果都是系统预定义的,开发人员不能对其进行自定义。导航的push方式呈现控制器的时候始终是从右到左的方式。在选择任何一个Tab的时候也没有任何动画效果。modal方式也是预定义的方式(默认方式是slide-up)。 除了这些限制之外,当过度到另一个界面之后,之前的界面就完全被遮盖,使得自定义modal窗口的方式不是那么好实现。 IOS7引入了自定义界面之间的过度方式,使得使用modal方式呈现界面变得非常容易了。cheers!:) 自定义的过度方式可以自由决定是否响应用户操作在过度期间,这里只是简单演示这个新的功能,所以就不在这方面下功夫了。 ~~~~~ 下面我就来做一个简单的Demo演示这个效果。 开始之前先理清思路。我们需要创建一个animator的对象负责对界面的展示和撤销加上动画效果,当展示view controll的时候将被展示的view controller的modalPresentationStyle设置为UIModalPresentationCustom,transitionDelegate设置为实现了UIViewControllerTransitioningDelegate这个协议的对象(本例为self)。 OK,let's code: 打开XCode,选择master-detail模板,填上相应的信息: 4FBFB69F-9CF0-404D-961A-FFF0FD937DA1   记得将master-detail的segue改为modal方式的: 4AE62009-5842-45AA-8073-F4D3AD0FA665
//实现UIViewControllerTransitioningDelegate
@interface TWMasterViewController : UITableViewController <NSFetchedResultsControllerDelegate,UIViewControllerTransitioningDelegate>
实现UIViewControllerTransitioningDelegate中得方法,
-(id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source{
    TWTransitionAnimator* animator = [TWTransitionAnimator new];
    animator.presenting = YES;
    return animator;
}

-(id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed{
    TWTransitionAnimator* animator = [TWTransitionAnimator new];
    return animator;
}
上面使用到的TWTransitionAnimator就是我们用来实现自定义界面展示效果的。这个类继承NSObject需要实现UIViewControllerAnimatedTransitioning这个协议:
@interface TWTransitionAnimator : NSObject <UIViewControllerAnimatedTransitioning>
@property (nonatomic,assign) BOOL presenting;
@end
其中定义了一个presenting属性,确定当前是否在展示modal窗口。UIViewControllerAnimatedTransitioning协议中必须实现的两个方法是:
-(NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext{
    return 0.5f;
}

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

}
第一个是过度所需的时间,第二个方法才是决定动画过度效果是如何呈现的。当过度开始的时候,transitionContext中包含了关于过度的信息。包含了from,to viewController和container view(动画实际进行的地方),需要将from,to控制器添加至这个container view,并执行一些过度效果,然后告诉这个context,过度已经完成了。看下面的实现:
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{
    UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

    [transitionContext.containerView addSubview:fromViewController.view];
    [transitionContext.containerView addSubview:toViewController.view];

    if(self.presenting){
        fromViewController.view.userInteractionEnabled = NO;

        [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0f usingSpringWithDamping:0.4 initialSpringVelocity:20 options:UIViewAnimationOptionCurveEaseInOut animations:^{
            fromViewController.view.alpha = 0.5f;
            toViewController.view.frame = CGRectInset(fromViewController.view.frame, 40, 40);
        } completion:^(BOOL finished) {
            [transitionContext completeTransition:finished];
        }];
    }else{

        [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
            toViewController.view.alpha = 1.0f;
            toViewController.view.userInteractionEnabled = YES;

            fromViewController.view.transform = CGAffineTransformRotate(toViewController.view.transform, -1.5);
        } completion:^(BOOL finished) {
            [transitionContext completeTransition:finished];
        }];
    }
}
这里的fromViewController和toViewController需要解释一下,当呈现modal的时候,from就是被遮盖的界面,modal就是to,当撤销modal界面的时候,from就是modal界面,而to则成了被遮盖的界面。 修改一下master界面的prepareForSegue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{

    TWDetailViewController* detail = segue.destinationViewController;
    detail.transitioningDelegate = self;
    detail.modalPresentationStyle = UIModalPresentationCustom;
}
在detail界面添加一个Button:click to dismiss用来撤销modal界面: 2B159B1C-1CEE-4C59-A28B-C42D392795A2
- (IBAction)dismissModalView:(id)sender {

    [self dismissViewControllerAnimated:YES completion:nil];
}
OK,可以看下效果图了: 612DDBA3-CC5F-40D8-A8DA-B2E83D5562D7 源代码放在gitOSC: TWModalView
展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部