• iOS_20_微博自己定义可动画切换的导航控制器


    终于效果:





    AnimatedNavigationController.h

    //
    //  AnimatedNavigationController.h
    //  20_帅哥no微博
    //
    //  Created by beyond on 14-8-10.
    //  Copyright (c) 2014年 com.beyond. All rights reserved.
    //  继承自导航控制器,可是多了一个功能,能够监听手势,进行动画切换
    
    #import <UIKit/UIKit.h>
    
    @interface AnimatedNavigationController : UINavigationController
    
    @end
    
    AnimatedNavigationController.m
    //
    //  AnimatedNavigationController.m
    //  20_帅哥no微博
    //
    //  Created by beyond on 14-8-10.
    //  Copyright (c) 2014年 com.beyond. All rights reserved.
    //
    
    
    #import "AnimatedNavigationController.h"
    // 截图用到
    #import <QuartzCore/QuartzCore.h>
    #import "BeyondViewController.h"
    @interface AnimatedNavigationController ()
    {
        // 屏幕截图
        UIImageView *_screenshotImgView;
        // 截图上面的黑色半透明遮罩
        UIView *_coverView;
        
        // 存放全部截图
        NSMutableArray *_screenshotImgs;
    }
    
    @end
    
    @implementation AnimatedNavigationController
    
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // 1,创建Pan手势识别器,并绑定监听方法
        UIPanGestureRecognizer *panGestureRec = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(panGestureRec:)];
        // 为导航控制器的view加入Pan手势识别器
        [self.view addGestureRecognizer:panGestureRec];
        
        
        
        // 2.创建截图的ImageView
        _screenshotImgView = [[UIImageView alloc] init];
        // app的frame是除去了状态栏高度的frame
        _screenshotImgView.frame = [UIScreen mainScreen].applicationFrame;
        //(0 20; 320 460);
        
        // 3.创建截图上面的黑色半透明遮罩
        _coverView = [[UIView alloc] init];
        // 遮罩的frame就是截图的frame
        _coverView.frame = _screenshotImgView.frame;
        // 遮罩为黑色
        _coverView.backgroundColor = [UIColor blackColor];
        
        // 4.存放全部的截图数组初始化
        _screenshotImgs = [NSMutableArray array];
        
        
        
    }
    
    
    
    // 重写push方法,在push之前 先截取图片
    - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
    {
        // 仅仅有在导航控制器里面有子控制器的时候才须要截图
        if (self.viewControllers.count >= 1) {
            // 调用自己定义方法,使用上下文截图
            [self screenShot];
        }
        // 截图完毕之后,才调用父类的push方法
        [super pushViewController:viewController animated:YES];
    }
    
    // 使用上下文截图,并使用指定的区域裁剪,模板代码
    - (void)screenShot
    {
        // 将要被截图的view,即窗体的根控制器的view(必须不含状态栏,默认ios7中控制器是包括了状态栏的)
        BeyondViewController *beyondVC = (BeyondViewController *)self.view.window.rootViewController;
        // 背景图片 总的大小
        CGSize size = beyondVC.view.frame.size;
        // 开启上下文,使用參数之后,截出来的是原图(YES  0.0 质量高)
        UIGraphicsBeginImageContextWithOptions(size, YES, 0.0);
        // 要裁剪的矩形范围
        CGRect rect = CGRectMake(0, -20.8, size.width, size.height + 20 );
        //注:iOS7以后renderInContext:由drawViewHierarchyInRect:afterScreenUpdates:替代
        [beyondVC.view drawViewHierarchyInRect:rect  afterScreenUpdates:NO];
        // 从上下文中,取出UIImage
        UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext();
        // 加入截取好的图片到图片数组
        [_screenshotImgs addObject:snapshot];
        
        // 千万记得,结束上下文(移除栈顶的基于当前位图的图形上下文)
        UIGraphicsEndImageContext();
        
    }
    
    
    // 监听手势的方法,仅仅要是有手势就会运行
    - (void)panGestureRec:(UIPanGestureRecognizer *)panGestureRec
    {
        
        // 假设当前显示的控制器已经是根控制器了,不须要做不论什么切换动画,直接返回
        if(self.topViewController == self.viewControllers[0]) return;
        // 推断pan手势的各个阶段
        switch (panGestureRec.state) {
            case UIGestureRecognizerStateBegan:
                // 開始拖拽阶段
                [self dragBegin];
                break;
                
            case UIGestureRecognizerStateEnded:
                // 结束拖拽阶段
                [self dragEnd];
                break;
                
            default:
                // 正在拖拽阶段
                [self dragging:panGestureRec];
                break;
        }
    }
    
    
    #pragma mark 開始拖动,加入图片和遮罩
    - (void)dragBegin
    {
        // 重点,每次開始Pan手势时,都要加入截图imageview 和 遮盖cover到window中
        [self.view.window insertSubview:_screenshotImgView atIndex:0];
        [self.view.window insertSubview:_coverView aboveSubview:_screenshotImgView];
        
        // 而且,让imgView显示截图数组中的最后(最新)一张截图
        _screenshotImgView.image = [_screenshotImgs lastObject];
    }
    
    
    // 默认的将要进行缩放的截图的初始比例
    #define kDefaultScale 0.6
    // 默认的将要变透明的遮罩的初始透明度(全黑)
    #define kDefaultAlpha 1.0
    
    // 当拖动的距离,占了屏幕的总宽度的3/4时, 就让imageview全然显示。遮盖全然消失
    #define kTargetTranslateScale 0.75
    #pragma mark 正在拖动,动画效果的精髓,进行缩放和透明度变化
    - (void)dragging:(UIPanGestureRecognizer *)pan
    {
    
        // 得到手指拖动的位移
        CGFloat offsetX = [pan translationInView:self.view].x;
        // 仅仅同意往右边拖,禁止向左拖
        if (offsetX < 0) offsetX = 0;
        // 让整个导航的view都平移     
        self.view.transform = CGAffineTransformMakeTranslation(offsetX, 0);
        
        // 计算眼下手指拖动位移占屏幕总的宽度的比例,当这个比例达到3/4时, 就让imageview全然显示。遮盖全然消失
        double currentTranslateScaleX = offsetX/self.view.frame.size.width;
        
        // 让imageview缩放,默认的比例+(当前平移比例/目标平移比例)*(1-默认的比例)
        double scale = kDefaultScale + (currentTranslateScaleX/kTargetTranslateScale) * (1 - kDefaultScale);
        // 已经达到原始大小了,就能够了,不用放得更大了
        if (scale > 1) scale = 1;
        _screenshotImgView.transform = CGAffineTransformMakeScale(scale, scale);
        
        // 让遮盖透明度改变,直到减为0,让遮罩全然透明,默认的比例-(当前平移比例/目标平移比例)*默认的比例
        double alpha = kDefaultAlpha - (currentTranslateScaleX/kTargetTranslateScale) * kDefaultAlpha;
        _coverView.alpha = alpha;
    }
    
    #pragma mark 结束拖动,推断结束时拖动的距离作对应的处理,并将图片和遮罩从父控件上移除
    - (void)dragEnd
    {
        // 取出挪动的距离
        CGFloat translateX = self.view.transform.tx;
        // 取出宽度
        CGFloat width = self.view.frame.size.width;
        
        if (translateX <= width * 0.5) {
            // 假设手指移动的距离还不到屏幕的一半,往左边挪 (弹回)
            [UIView animateWithDuration:0.3 animations:^{
                // 重要~~让被右移的view弹回归位,仅仅要清空transform就可以办到
                self.view.transform = CGAffineTransformIdentity;
                // 让imageView大小恢复默认的scale
                _screenshotImgView.transform = CGAffineTransformMakeScale(kDefaultScale, kDefaultScale);
                // 让遮盖的透明度恢复默认的alpha 1.0
                _coverView.alpha = kDefaultAlpha;
            } completion:^(BOOL finished) {
                // 重要,动画完毕之后,每次都要记得 移除两个view,下次開始拖动时,再加入进来
                [_screenshotImgView removeFromSuperview];
                [_coverView removeFromSuperview];
            }];
        } else {
            // 假设手指移动的距离还超过了屏幕的一半,往右边挪
            [UIView animateWithDuration:0.3 animations:^{
                // 让被右移的view全然挪到屏幕的最右边,结束之后,还要记得清空view的transform
                self.view.transform = CGAffineTransformMakeTranslation(width, 0);
                // 让imageView缩放置为1
                _screenshotImgView.transform = CGAffineTransformMakeScale(1, 1);
                // 让遮盖alpha变为0,变得全然透明
                _coverView.alpha = 0;
            } completion:^(BOOL finished) {
                // 重要~~让被右移的view全然挪到屏幕的最右边,结束之后,还要记得清空view的transform,不然下次再次開始drag时会出问题,由于view的transform没有归零
                self.view.transform = CGAffineTransformIdentity;
                // 移除两个view,下次開始拖动时,再加回来
                [_screenshotImgView removeFromSuperview];
                [_coverView removeFromSuperview];
                
                // 运行正常的Pop操作:移除栈顶控制器,让真正的前一个控制器成为导航控制器的栈顶控制器
                [self popViewControllerAnimated:NO];
                
                // 重要~记得这时候,能够移除截图数组里面最后一张无用的截图了
                [_screenshotImgs removeLastObject];
            }];
        }
    }
    @end
    





  • 相关阅读:
    山寨 《寻找房祖名》
    css3 弹性效果上下翻转demo
    CSS3 Hover 动画特效
    判断一个字符串通过变化字符的位置,是否可以组成回文
    获取多个字符串中的共同字符
    转换为回文的步数
    IOS中图片的一些处理方法
    python django的一点笔记
    一个图片切割的例子
    一个批量修改文件夹中文件名的命令
  • 原文地址:https://www.cnblogs.com/jzssuanfa/p/6844507.html
Copyright © 2020-2023  润新知