你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS_20_微博自定義可動畫切換的導航控制器

iOS_20_微博自定義可動畫切換的導航控制器

編輯:IOS開發綜合

最終效果:



\


AnimatedNavigationController.h

//
//  AnimatedNavigationController.h
//  20_帥哥no微博
//
//  Created by beyond on 14-8-10.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  繼承自導航控制器,但是多了一個功能,可以監聽手勢,進行動畫切換

#import 

@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 
#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





  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved