iOS動畫效果八:實現(xiàn)類似系統(tǒng)的測滑返回效果

這篇文章主要介紹怎樣實現(xiàn)類似系統(tǒng)的測滑返回效果
最終的效果圖為:


自定義測滑返回手勢.gif

Demo地址為:
Demo地址

對應的實現(xiàn)文件為:
EightViewController、CustomPopGestureViewController、PopAnimation

關于轉場動畫,下面這張圖將的很清楚


轉場動畫的相關類和協(xié)議的方法

為了實現(xiàn)類似系統(tǒng)的測滑返回效果,實際上就是pop的自定義返回動畫,再加上UIPanGestureRecognizer手勢的交互實現(xiàn),也就是交互性轉場動畫(因為根據(jù)手指滑動的距離,大于一半會pop到上一個瀏覽器,小于一半會恢復原狀)

由上面的圖可以看到,想要實現(xiàn)交互性轉場動畫,需要實現(xiàn)UIViewControllerInteractiveTransitioning,
但是系統(tǒng)有給我們提供一個可交互的百分比動畫實現(xiàn)類,即UIPerCententDrivenInteractiveTransition,
在接下來的實現(xiàn)中,我們可以直接使用系統(tǒng)提供的實現(xiàn)類,也可以自定義一個遵守UIViewControllerInteractiveTransitioning協(xié)議的類(我們是使用了系統(tǒng)提供的)

首先,我們先把pop動畫的自定義給完成
在eightViewController中,搭建基本的界面,可以push到CustomPopGestureViewController中
在eightViewController.h中

@property (nonatomic, strong) UIButton *button;

在eightViewController.m中

- (void)viewDidLoad {
    [super viewDidLoad];
    self.title = @"測滑返回手勢測試";
    self.navigationController.navigationBar.translucent = NO;
    self.view.backgroundColor = [UIColor whiteColor];
    
    self.button.center = self.view.center;
    [self.view addSubview:self.button];
}

- (UIButton *)button {
    if (_button) {
        return _button;
    }
    _button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 100, 50)];
    [_button setTitle:@"跳轉下一個播放器" forState:UIControlStateNormal];
    [_button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [_button addTarget:self action:@selector(buttonClicked) forControlEvents:UIControlEventTouchUpInside];
    return _button;
}

- (void)buttonClicked {
    NSLog(@"點擊了跳轉按鈕");
    CustomPopGestureViewController *vc = [[CustomPopGestureViewController alloc] init];
    [self.navigationController pushViewController:vc animated:YES];
}

點擊按鈕,可以push到CustomGestureViewcontroller中

為了實現(xiàn)自定義的測滑返回功能,我們需要禁用系統(tǒng)的測滑返回功能
在CustomViewController中,我們需要添加以下代碼禁用

 //禁用系統(tǒng)自帶的側滑返回手勢
    self.navigationController.interactivePopGestureRecognizer.enabled = NO;

接下來,先實現(xiàn)pop的自定義動畫
在CustomViewController中,需要遵守UINavigationDelegate協(xié)議

self.navigationController.delegate = self;

實現(xiàn)相應的協(xié)議方法

- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC {
    if (operation == UINavigationControllerOperationPop) {
        NSLog(@"執(zhí)行了這個方法PopAnimation");
      //popAnimation是我們后面定義的類,用來實現(xiàn)具體的動畫效果
        return [[PopAnimation alloc] init];
    }
    return nil;
}

接下來,我們自定義一個類PopAnimation,遵守協(xié)議UIViewControllerAnimatedTransitioning
在類中實現(xiàn)相應的協(xié)議方法

//設置動畫執(zhí)行的時常
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
    return 1.0f;
}

//用來處理具體的動畫
- (void)animateTransition:(nonnull id<UIViewControllerContextTransitioning>)transitionContext {
    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    //需要將轉場后的界面給加上去才行
//    [[transitionContext containerView] addSubview:toVC.view];
    [[transitionContext containerView] insertSubview:toVC.view belowSubview:fromVC.view];
    NSTimeInterval duration = [self transitionDuration:transitionContext];
    CGFloat width = [UIScreen mainScreen].bounds.size.width;
    CGFloat height = [UIScreen mainScreen].bounds.size.height;
    [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
        fromVC.view.frame = CGRectMake(width, 0, width, height);
    } completion:^(BOOL finished) {
        [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
    }];
}

上面實現(xiàn)動畫的思路:

我們可以從最終效果圖上可以看成:
pop動畫的過程就是將上面的view向右挪動,直到移出界面
所以代碼中有這一句
[[transitionContext containerView] insertSubview:toVC.view belowSubview:fromVC.view];
將toView的view放在fromVC.view的下面,使用UIview animation來完成移動動畫

注意:這里只能使用UIView animation來完成動畫,代碼中注釋的是我最初使用CABasicAnimation來完成移動動畫,pop自定義動畫可行,但是對于后面使用系統(tǒng)類UIPerCententDrivenInteractiveTransition完成交互不可行,
如果想要使用CaBasicAnimation,必須自定義可交互的百分比動畫類

這樣我們就完成了pop的自定義動畫返回,但是我們需要加入交互,通過判斷手指滑動的距離來判斷動畫的進行程度

接下來,我們需要在CustomPopGestureViewController中,定義相應的手勢屬性和相應的交互類

@property (nonatomic, strong) UIPanGestureRecognizer *pan;
@property (nonatomic, strong) UIPercentDrivenInteractiveTransition *interactiveTransition;

接下來完成相應的手勢類的添加

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    self.title = @"類似系統(tǒng)側滑返回手勢實現(xiàn)";
    self.navigationController.navigationBar.translucent = NO;
    self.view.backgroundColor = [UIColor yellowColor];
    
    //禁用系統(tǒng)自帶的側滑返回手勢
    self.navigationController.interactivePopGestureRecognizer.enabled = NO;
    
    [self.view addGestureRecognizer:self.pan];
    
    self.navigationController.delegate = self;
}

- (UIPanGestureRecognizer *)pan {
    if (_pan) {
        return _pan;
    }
    _pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
    return _pan;
}

在手勢類的出發(fā)方法中,我們需要根據(jù)UIPanGestureRecognizer的狀態(tài)來初始化或者更新或者取消或者結束交互類

UIGestureRecognizerStateBegan:手勢類剛開始出發(fā)時,初始化相應的interactiveTransition
UIGestureRecognizerStateChanged:手勢繼續(xù)滑動的時候,交互類進行相應的更新
UIGestureRecognizerStateEnded:手勢結束時,交互類結束
UIGestureRecognizerStateCancelled:手勢取消時,交互類取消
最后一個手勢周期完成后都要將交互類interactiveTransition置為nil

代碼為:

- (void)pan:(UIPanGestureRecognizer *)pan {
    if (self.navigationController.childViewControllers.count == 1) {
        return;
    }
    CGPoint point = [pan translationInView:self.view];
    CGFloat percent = point.x / self.view.bounds.size.width;
    NSLog(@"percent的進度值為:%f",percent);
    percent = MIN(MAX(0, percent), 1);
    if (pan.state == UIGestureRecognizerStateBegan) {
        _interactiveTransition = [[UIPercentDrivenInteractiveTransition alloc] init];
        [self.navigationController popViewControllerAnimated:YES];
    } else if (pan.state == UIGestureRecognizerStateChanged) {
        [_interactiveTransition updateInteractiveTransition:percent];
    } else if (pan.state == UIGestureRecognizerStateEnded || pan.state == UIGestureRecognizerStateCancelled) {
        //手勢結束后,若進度大于0.5就完成pop動畫,否則取消
        if (percent > 0.5) {
            [_interactiveTransition finishInteractiveTransition];
        } else {
            [_interactiveTransition cancelInteractiveTransition];
        }
        _interactiveTransition = nil;
    }
}

另外,不要忘記,在UINavigationDelegate協(xié)議方法中實現(xiàn)可交互類的協(xié)議方法

- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController {
    if ([animationController isKindOfClass:[PopAnimation class]]) {
        NSLog(@"執(zhí)行了這個方法UIPercentDrivenInteractiveTransition");
        return _interactiveTransition;
    }
    return nil;
}

最終的效果圖為:


自定義測滑返回手勢.gif

總結

最終效果圖為:


自定義測滑返回手勢.gif

Demo地址為:
Demo地址

iOS開發(fā)中動畫效果的探究(一)

iOS動畫效果的探究二:UIView Animation實現(xiàn)動畫

iOS動畫效果三:CABAsicAnimation實現(xiàn)平移、旋轉和放大

ios動畫效果四:使用Pop框架實現(xiàn)彈簧效果

iOS動畫效果五:CABasicAnimation實現(xiàn)繞定點旋轉的效果]

iOS動畫效果六:實現(xiàn)自定義的push轉場動畫

iOS動畫效果七:實現(xiàn)自定義present轉場動畫效果

iOS動畫效果八:實現(xiàn)類似系統(tǒng)的測滑返回效果

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容