像Instagram iPhone应用程序一样向右滑动时导航弹出视图。我如何实现这一目标? [英] Navigation pop view when swipe right like Instagram iPhone app.How i achieve this?

查看:112
本文介绍了像Instagram iPhone应用程序一样向右滑动时导航弹出视图。我如何实现这一目标?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在屏幕上向右滑动时弹出一个视图,或者它像导航栏的后退按钮一样工作。



我正在使用:

  self.navigationController.interactivePopGestureRecognizer.delegate =(id< UIGestureRecognizerDelegate>)self; 

流行导航视图的这一行代码,这对我来说很有用,但是当我向中间滑动时屏幕这不会像Instagram iPhone应用程序一样。



在这里我给出一个Instagram应用程序的屏幕,你可以看到滑动右侧弹出导航视图的示例: / p>

解决方案

Apple自动实现向右滑动VC仅适用于屏幕左侧~20点。这样,他们确保他们不会弄乱您的应用程序的功能。想象一下,屏幕上有一个 UIScrollView ,你无法向右滑动,因为它会不断弹出VC。这不太好。



Apple说在其中


interactivePopGestureRecognizer



手势识别器负责将顶视图控制器弹出导航堆栈。 (只读)



@property(非原子,只读)UIGestureRecognizer * interactivePopGestureRecognizer



导航控制器安装此手势识别器在其视图
上并使用它从导航
堆栈中弹出最顶层的视图控制器。您可以使用此属性检索手势识别器
并将其与用户
界面中其他手势识别器的行为联系起来。将手势识别器绑在一起时,请确保
他们同时识别他们的手势,以确保您的
手势识别器有机会处理该事件。


因此,您必须实现自己的 UIGestureRecognizer ,并将其行为与 interactivePopGestureRecognizer 你的 UIViewController






编辑:



这是我建立的解决方案。您可以实现符合 UIViewControllerAnimatedTransitioning 委托的自己的转换。此解决方案有效,但尚未经过全面测试。



您将获得交互式滑动转换以弹出您的ViewControllers。您可以从视图中的任何位置向右滑动。



已知问题:如果启动平移并在视图宽度的一半之前停止,则转换将被取消(预期行为)。在此过程中,视图将重置为其原始帧。在这个动画中,它们是一个视觉故障。



示例的类如下:


UINavigationController> ViewController> SecondViewController


CustomPopTr​​ansition.h

  #import< Foundation / Foundation.h> 

@interface CustomPopTr​​ansition:NSObject< UIViewControllerAnimatedTransitioning>

@end

CustomPopTr​​ansition.m

  #importCustomPopTr​​ansition.h
#importSecondViewController.h
#importViewController .h

@implementation CustomPopTr​​ansition

- (NSTimeInterval)transitionDuration:(id< UIViewControllerContextTransitioning>)transitionContext {
return 0.3;
}

- (void)animateTransition:(id< UIViewControllerContextTransitioning>)transitionContext {

SecondViewController * fromViewController =(SecondViewController *)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
ViewController * toViewController =(ViewController *)[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

UIView * containerView = [transitionContext containerView];
[containerView addSubview:toViewController.view];
[containerView bringSubviewToFront:fromViewController.view];

//设置初始视图状态
toViewController.view.frame = [transitionContext finalFrameForViewController:toViewController];

[UIView animateWithDuration:0.3动画:^ {

fromViewController.view.frame = CGRectMake(toViewController.view.frame.size.width,fromViewController.view.frame.origin .y,fromViewController.view.frame.size.width,fromViewController.view.frame.size.height);

}完成:^(BOOL完成){

//声明我们已完成
[transitionContext completeTransition:!transitionContext.transitionWasCancelled];
}];

}

@end

SecondViewController.h

  #import< UIKit / UIKit.h> 

@interface SecondViewController:UIViewController< UINavigationControllerDelegate>

@end

SecondViewController.m

  #importSecondViewController.h
#importViewController.h
#importCustomPopTr​​ansition .h

@interface SecondViewController()

@property(nonatomic,strong)UIPercentDrivenInteractiveTransition * interactivePopTr​​ansition;

@end

@implementation SecondViewController

- (void)viewDidLoad
{
[super viewDidLoad];

self.navigationController.delegate = self;

UIPanGestureRecognizer * popRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePopRecognizer :)];
[self.view addGestureRecognizer:popRecognizer];
}

- (void)viewDidDisappear:(BOOL)动画{

[super viewDidDisappear:animated];

//停止成为导航控制器的委托
if(self.navigationController.delegate == self){
self.navigationController.delegate = nil;
}
}

- (id< UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation :( UINavigationControllerOperation)操作fromViewController:(UIViewController *)fromVC toViewController:(UIViewController * )toVC {

//检查我们是否从这个视图控制器转换到DSLSecondViewController
if(fromVC == self&& [toVC isKindOfClass:[ViewController class]]) {
return [[CustomPopTr​​ansition alloc] init];
}
else {
return nil;
}
}

- (id< UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id< UIViewControllerAnimatedTransitioning>)animationController {

//检查这是否适用于我们的自定义转换
if([animationController isKindOfClass:[CustomPopTr​​ansition class]]){
return self.interactivePopTr​​ansition;
}
else {
return nil;
}
}

- (void)handlePopRecognizer:(UIPanGestureRecognizer *)识别器{

//计算用户拖过视图的距离
CGFloat进度= [识别器translationInView:self.view] .x /(self.view.bounds.size.width * 1.0);
progress = MIN(1.0,MAX(0.0,progress));

if(recognizer.state == UIGestureRecognizerStateBegan){
NSLog(@started);
//创建交互式转换并弹出视图控制器
self.interactivePopTr​​ansition = [[UIPercentDrivenInteractiveTransition alloc] init];
[self.navigationController popViewControllerAnimated:YES];
}
else if(recognizer.state == UIGestureRecognizerStateChanged){
NSLog(@changed);
//更新交互式转换的进度
[self.interactivePopTr​​ansition updateInteractiveTransition:progress];
}
else if(recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled){
NSLog(@已结束/已取消);
//完成或取消交互式转换
if(progress> 0.5){
[self.interactivePopTr​​ansition finishInteractiveTransition];
}
else {
[self.interactivePopTr​​ansition cancelInteractiveTransition];
}

self.interactivePopTr​​ansition = nil;
}
}

@end


I want to pop a view when swipe right on screen or it's work like back button of navigation bar.

I am using:

self.navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self;

This single line of code for pop navigation view and it's a work for me but when i swipe form middle of screen this will not work like Instagram iPhone app.

Here i give a one screen of Instagram app in that you can see the Example of swipe right pop navigation view:

解决方案

Apple's automatic implementation of the "swipe right to pop VC" only works for the left ~20 points of the screen. This way, they make sure they don't mess with your app's functionalities. Imagine you have a UIScrollView on screen, and you can't swipe right because it keeps poping VCs out. This wouldn't be nice.

Apple says here :

interactivePopGestureRecognizer

The gesture recognizer responsible for popping the top view controller off the navigation stack. (read-only)

@property(nonatomic, readonly) UIGestureRecognizer *interactivePopGestureRecognizer

The navigation controller installs this gesture recognizer on its view and uses it to pop the topmost view controller off the navigation stack. You can use this property to retrieve the gesture recognizer and tie it to the behavior of other gesture recognizers in your user interface. When tying your gesture recognizers together, make sure they recognize their gestures simultaneously to ensure that your gesture recognizers are given a chance to handle the event.

So you will have to implement your own UIGestureRecognizer, and tie its behavior to the interactivePopGestureRecognizer of your UIViewController.


Edit :

Here is a solution I built. You can implement your own transition conforming to the UIViewControllerAnimatedTransitioning delegate. This solution works, but has not been thoroughly tested.

You will get an interactive sliding transition to pop your ViewControllers. You can slide to right from anywhere in the view.

Known issue : if you start the pan and stop before half the width of the view, the transition is canceled (expected behavior). During this process, the views reset to their original frames. Their is a visual glitch during this animation.

The classes of the example are the following :

UINavigationController > ViewController > SecondViewController

CustomPopTransition.h :

#import <Foundation/Foundation.h>

@interface CustomPopTransition : NSObject <UIViewControllerAnimatedTransitioning>

@end

CustomPopTransition.m :

#import "CustomPopTransition.h"
#import "SecondViewController.h"
#import "ViewController.h"

@implementation CustomPopTransition

- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
    return 0.3;
}

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {

    SecondViewController *fromViewController = (SecondViewController*)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    ViewController *toViewController = (ViewController*)[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

    UIView *containerView = [transitionContext containerView];
    [containerView addSubview:toViewController.view];
    [containerView bringSubviewToFront:fromViewController.view];

    // Setup the initial view states
    toViewController.view.frame = [transitionContext finalFrameForViewController:toViewController];

    [UIView animateWithDuration:0.3 animations:^{

        fromViewController.view.frame = CGRectMake(toViewController.view.frame.size.width, fromViewController.view.frame.origin.y, fromViewController.view.frame.size.width, fromViewController.view.frame.size.height);

    } completion:^(BOOL finished) {

        // Declare that we've finished
        [transitionContext completeTransition:!transitionContext.transitionWasCancelled];
    }];

}

@end

SecondViewController.h :

#import <UIKit/UIKit.h>

@interface SecondViewController : UIViewController <UINavigationControllerDelegate>

@end

SecondViewController.m :

#import "SecondViewController.h"
#import "ViewController.h"
#import "CustomPopTransition.h"

@interface SecondViewController ()

@property (nonatomic, strong) UIPercentDrivenInteractiveTransition *interactivePopTransition;

@end

@implementation SecondViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.navigationController.delegate = self;

    UIPanGestureRecognizer *popRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePopRecognizer:)];
    [self.view addGestureRecognizer:popRecognizer];
}

-(void)viewDidDisappear:(BOOL)animated {

    [super viewDidDisappear:animated];

    // Stop being the navigation controller's delegate
    if (self.navigationController.delegate == self) {
        self.navigationController.delegate = nil;
    }
}

- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC {

    // Check if we're transitioning from this view controller to a DSLSecondViewController
    if (fromVC == self && [toVC isKindOfClass:[ViewController class]]) {
        return [[CustomPopTransition alloc] init];
    }
    else {
        return nil;
    }
}

- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController {

    // Check if this is for our custom transition
    if ([animationController isKindOfClass:[CustomPopTransition class]]) {
        return self.interactivePopTransition;
    }
    else {
        return nil;
    }
}

- (void)handlePopRecognizer:(UIPanGestureRecognizer*)recognizer {

    // Calculate how far the user has dragged across the view
    CGFloat progress = [recognizer translationInView:self.view].x / (self.view.bounds.size.width * 1.0);
    progress = MIN(1.0, MAX(0.0, progress));

    if (recognizer.state == UIGestureRecognizerStateBegan) {
        NSLog(@"began");
        // Create a interactive transition and pop the view controller
        self.interactivePopTransition = [[UIPercentDrivenInteractiveTransition alloc] init];
        [self.navigationController popViewControllerAnimated:YES];
    }
    else if (recognizer.state == UIGestureRecognizerStateChanged) {
        NSLog(@"changed");
        // Update the interactive transition's progress
        [self.interactivePopTransition updateInteractiveTransition:progress];
    }
    else if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled) {
        NSLog(@"ended/cancelled");
        // Finish or cancel the interactive transition
        if (progress > 0.5) {
            [self.interactivePopTransition finishInteractiveTransition];
        }
        else {
            [self.interactivePopTransition cancelInteractiveTransition];
        }

        self.interactivePopTransition = nil;
    }
}

@end

这篇关于像Instagram iPhone应用程序一样向右滑动时导航弹出视图。我如何实现这一目标?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆