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都平移     // 挪动整个导航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

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

时间: 2024-10-11 18:27:40

iOS_20_微博自定义可动画切换的导航控制器的相关文章

iOS_20_微博Dock的跟随切换

最终效果图:Dock跟随HomeVC一起切换 要求: 当点击HomeVC里面的微博列表的某一行时候, push到StatusDetail微博详情控制器,并且Dock也一起消失 当点击StatusDetail微博详情控制器上面的左边返回按钮,Dock也跟着HomeVC一起回来 HomeVC.m // 点击列表中的一条微博,创建一个StatusDetailViewController,并为其成员status赋值(数据来源),并通过导航push入栈 - (void)tableView:(UITable

iOS_20_微博Dock的尾随切换

终于效果图:Dock尾随HomeVC一起切换 要求: 当点击HomeVC里面的微博列表的某一行时候, push到StatusDetail微博详情控制器,而且Dock也一起消失 当点击StatusDetail微博详情控制器上面的左边返回button,Dock也跟着HomeVC一起回来 HomeVC.m // 点击列表中的一条微博,创建一个StatusDetailViewController,并为其成员status赋值(数据来源),并通过导航push入栈 - (void)tableView:(UIT

iOS 自定义页面的切换动画与交互动画

在iOS7之前,开发者为了寻求自定义Navigation Controller的Push/Pop动画,只能受限于子类化一个UINavigationController,或是用自定义的动画去覆盖它.但是随着iOS7的到来,Apple针对开发者推出了新的工具,以更灵活地方式管理UIViewController切换. 自定义导航栏的Push/Pop动画 为了在基于UINavigationController下做自定义的动画切换,先建立一个简单的工程,这个工程的rootViewController是一个

iOS 自定义页面的切换动画与交互动画 By Swift(转)

交互动画切换动画Swiftiosios7 目录(?)[-] 最终效果预览 自定义导航栏的PushPop动画 自定义Modal的PresentDismiss动画 自定义导航栏的交互式动画 使用UIPercentDrivenInteractiveTransition 自定义交互控制器 最终效果 UPDATED 在iOS7之前,开发者为了寻求自定义Navigation Controller的Push/Pop动画,只能受限于子类化一个UINavigationController,或是用自定义的动画去覆盖

自定义ModalViewController 动画效果

iOS 7 自定义ViewController动画切换 自定义动画切换的相关的主要API 在深入之前,我们先来看看新SDK中有关这部分内容的相关接口以及它们的关系和典型用法.这几个接口和类的名字都比较相似,但是还是能比较好的描述出各自的职能的,一开始的话可能比较迷惑,但是当自己动手实现一两个例子之后,它们之间的关系就会逐渐明晰起来.(相关的内容都定义在UIKit的UIViewControllerTransitioning.h中了) @protocol UIViewControllerContex

【iOS开发-24】导航控制器下不同视图控制器之间切换:利用CATrasition和view的layer层来实现自定义的动画效果

(1)这里的动画效果指的是界面切换的动画效果,我们常见的又淡入淡出,右出左进等等,当然还有一些高级动画,这种动画适合游戏类的,对于一般APP会显得太花哨. (2)我们在此处没有增加任何框架(QuartzCore)也没有导入什么头文件(QuartzCore.h),就可以直接用CATransiton(相当于是CAAnimation的子类)来创建一个对象,如animation1. (3)创建完之后我们就对这个动画对象进行动画设置,这里面主要是涉及到type属性,而且值有两种:一种是调用系统自带的一些效

猫猫学iOS 之微博项目实战(2)微博主框架-自定义导航控制器NavigationController

猫猫分享,必须精品 原创文章,欢迎转载.转载请注明:翟乃玉的博客 地址:http://blog.csdn.net/u013357243?viewmode=contents 一:添加导航控制器 上一篇博客完成了对底部的TabBar的设置,这一章我们完成自定义导航控制器(NYNavigationController). 为啥要做自定义呢,因为为了更好地封装代码,并且系统的UINavigationController不能满足我们的需求了,所以得自定义. 首先,我们在NYTabBarViewContro

Android实例-手机安全卫士(二十一)-自定义Activity界面切换动画

一.目标. 实现两个Activity界面的动画切换效果. 二.代码实现. 1.在res文件夹下新建一个名为anim的文件夹. 2.在新建的anim文件夹中新建一个Android xml file文件(取名tran_out),根据动画要求选择根元素(本例为translate),用于实现Activity界面移出屏幕的动画效果. 3.在新建的xml文件中,根标签<translate>的属性中,当输入一个属性时会自动增加命名空间.属性android:fromXDelta表示从哪个X轴来,原点为屏幕左上

iOS_20_微博『更多』页面

最终效果图: MoreViewController.m // // MoreViewController.m // 20_帅哥no微博 // // Created by beyond on 14-8-4. // Copyright (c) 2014年 com.beyond. All rights reserved. // #import "MoreViewController.h" @interface MoreViewController () { // more.plist根是字典