手势移除控制器(UIPanGestureRecognizer + UINavigationController)

//
//  CZNavigationController.m
//  手势移除控制器
//
//  Created by pkxing on 14/12/10.
//  Copyright (c) 2014年 梦醒. All rights reserved.
//

// 图片透明度最小值
#define PKMinAlpha 0.5
// 动画时间
#define PKDuration 0.1
// 手势最大速率
#define PKMaxVelocity 800
// 阴影不透明度
#define PKShadowOpacity 0.3
// 阴影偏移量
#define PKShadowOffset  CGSizeMake(-3, 0)
// 阴影颜色
#define PKShadowColor  [UIColor blackColor].CGColor
#import "CZNavigationController.h"
@interface CZNavigationController()<UINavigationControllerDelegate>
/** 所有控制器截图 */
@property(nonatomic,strong) NSMutableArray *images;
/** 左边显示的 imageView */
@property(nonatomic,strong) UIImageView *imageView;
/** 导航控制器view的宽度 */
@property(nonatomic,assign) CGFloat  viewWidth;
/** 子控制器的个数 */
@property(nonatomic,assign) int  vcCount;
@end

@implementation CZNavigationController

#pragma mark - 懒加载方法
/**
 *  懒加载 imageView。
 */
- (UIImageView *)imageView {
    if(_imageView == nil) {
        _imageView = [[UIImageView alloc] init];
        CGRect frame = self.view.bounds;
        frame.origin.x -= frame.size.width;
        _imageView.frame = frame;
        [self.view insertSubview:_imageView belowSubview:self.navigationBar];
    }
    return _imageView;
}

- (NSMutableArray *)images {
    if (_images == nil) {
        _images = [NSMutableArray array];
    }
    return  _images;
}
#pragma mark - 生命周期方法
- (void)viewDidLoad {
    [super viewDidLoad];
    self.viewWidth = self.view.frame.size.width;
    // KVO监听vcCount值的变化
    [self addObserver];
    // 设置代理
    self.delegate = self;
    // 添加拖拽手势
    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(draging:)];
    [self.view addGestureRecognizer:pan];
}

- (void)dealloc {
    [self removeObserver];
}

#pragma mark - KVO 属性监听方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if ([keyPath isEqualToString:@"vcCount"]) {
        [self captureScreenShot];
    }
}

- (void)addObserver{
    [self addObserver:self forKeyPath:@"vcCount" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
}
- (void)removeObserver{
    [self removeObserver:self forKeyPath:@"vcCount"];
}

#pragma mark - 监听拖拽手势
/**
 *  监听拖拽手势
 */
- (void)draging:(UIPanGestureRecognizer *)recognizer{
    // 如果导航控制器中只有一个子控制器,则不响应拖拽手势
    if (self.viewControllers.count <= 1) return;
    // 获得拖拽的位置
    CGPoint translationPoint = [recognizer translationInView:self.view];
    // 获得水平方法平移的值
    CGFloat translationX = translationPoint.x;
    // 只能向左拖拽(translationX<0表示往右边拖拽)
    if (translationX <= 0){
        [self settingTransform:0.0];
        return;
    }
    // 手势结束或手势被取消
    if (recognizer.state == UIGestureRecognizerStateEnded
        || recognizer.state == UIGestureRecognizerStateCancelled || recognizer.state == UIGestureRecognizerStatePossible  || recognizer.state == UIGestureRecognizerStateFailed) { // 拖拽结束或正在拖拽
        // 计算拖拽速度
        CGPoint velocity = [recognizer velocityInView:self.view];
        // 每秒移动多少个点
        CGFloat magnitude = sqrtf((velocity.x * velocity.x) + (velocity.y * velocity.y));
        
        // 如果拖拽速度大于PKMaxVelocity 或 拖拽距离大于导航控制器view宽度的一半,则出栈
        BOOL pop = (magnitude > PKMaxVelocity) || (translationX > self.viewWidth * 0.5);
        [UIView animateWithDuration:PKDuration delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
            [self settingTransform:(pop ? self.viewWidth :0)];
        } completion:^(BOOL finished) {
            if (pop) {
                [self popViewControllerAnimated:NO];
                [self settingTransform:0];
                self.vcCount = self.viewControllers.count;
            }
            [_imageView removeFromSuperview];
            _imageView = nil;
        }];
    } else if(recognizer.state == UIGestureRecognizerStateBegan) { // 开始拖拽
        [self.view sendSubviewToBack:self.imageView];
        self.topViewController.view.layer.shadowOffset = PKShadowOffset;
        self.topViewController.view.layer.shadowColor = PKShadowColor;
        self.topViewController.view.layer.shadowOpacity = PKShadowOpacity;
    } else { // 正在拖拽
        if (self.imageView.image == nil) {
            self.imageView.image = [self.images lastObject];
        }
        // 移动导航控制器的view和imageView
        [self settingTransform:translationX];
    }
}

/**
 *  设置导航控制器和imageView的transform
 */
- (void)settingTransform:(CGFloat)translationX{
    self.topViewController.view.layer.transform = CATransform3DMakeTranslation(translationX, 0, 0);
    self.imageView.layer.transform = CATransform3DMakeTranslation(translationX, 0, 0);
    if (translationX == 0) {
        self.topViewController.view.layer.shadowOpacity = 0.0;
        self.navigationBar.alpha = 1.0;
    } else {
        // 控制imageView 的透明度
        CGFloat alpha = 1 - (translationX / self.viewWidth);
        self.navigationBar.alpha = MAX(0.8, alpha);
    }
}

/**
 *  屏幕截图
 */
- (void)captureScreenShot{
    [self.images removeAllObjects];
    int count = self.viewControllers.count;
    if (count <= 1) return;
    dispatch_async(dispatch_get_main_queue(), ^{
        UIViewController *controller = self.viewControllers[count - 2];
        UIGraphicsBeginImageContextWithOptions(self.view.frame.size, YES, 0.0);
        [controller.view.layer renderInContext:UIGraphicsGetCurrentContext()];
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        [self.images addObject:image];
    });
}

#pragma mark - UINavigationControllerDelegate 方法
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
    self.vcCount = self.viewControllers.count;
}
@end


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
iOS中的导航控制器UINavigationController)是一种视图控制器容器,用于管理应用程序中的多个视图控制器。它是一种实现iOS中视图控制器之间导航的常用方式,可以使用它来管理应用程序的层级结构。 导航控制器的工作原理如下: 1. 创建导航控制器 在应用程序中创建一个导航控制器,然后将第一个视图控制器添加到该导航控制器中。 ``` let navController = UINavigationController(rootViewController: firstViewController) ``` 2. 添加视图控制器 使用以下方法将要显示的视图控制器添加到导航控制器中。 ``` navController.pushViewController(secondViewController, animated: true) ``` 3. 返回视图控制器 使用以下方法将当前显示的视图控制器返回到导航控制器中的上一个视图控制器。 ``` navController.popViewController(animated: true) ``` 举例来说,假设我们有一个简单的应用程序,它有三个视图控制器:`ViewController1`,`ViewController2`和`ViewController3`。我们通过以下代码创建一个导航控制器,并将`ViewController1`添加为第一个视图控制器: ``` let navController = UINavigationController(rootViewController: ViewController1()) ``` 当用户在`ViewController1`中点击按钮时,我们将跳转到`ViewController2`。我们可以使用以下代码将`ViewController2`添加到导航控制器中: ``` navController.pushViewController(ViewController2(), animated: true) ``` 当用户在`ViewController2`中点击返回按钮时,我们将返回到`ViewController1`。我们可以使用以下代码将当前显示的视图控制器返回到导航控制器中的上一个视图控制器: ``` navController.popViewController(animated: true) ``` 当用户在`ViewController2`中点击另一个按钮时,我们将跳转到`ViewController3`。我们可以使用以下代码将`ViewController3`添加到导航控制器中: ``` navController.pushViewController(ViewController3(), animated: true) ``` 这就是导航控制器的基本工作原理和用法。它可以使我们方便地管理应用程序的视图控制器层级结构,并实现视图控制器之间的导航。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fkjaios_xkp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值