2014-03-07 8 views
15

Ich möchte eine Ansicht öffnen, wenn Sie auf dem Bildschirm nach rechts wischen, oder es funktioniert wie der Zurück-Button der Navigationsleiste.Navigation Pop-Ansicht, wenn swipe rechts wie Instagram iPhone app.Wie erreiche ich das?

Ich verwende:

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

Diese einzige Zeile Code für Ansicht pop Navigation und es ist eine Arbeit für mich, aber wenn ich Form Mitte des Bildschirms Swipe wird dies nicht wie App Instagram iPhone arbeiten.

Hier gebe ich einen einen Bildschirm von Instagram App auf, dass Sie das Beispiel von Swipe rechts Pop Navigationsansicht sehen:

enter image description here

+0

Sie diese Frage folgen (es hat noch keine Antworten, aber es ist ein Duplikat): http://stackoverflow.com/questions/20714595/extend-default-interactivepopgesture_recognizer-beyond-screen-edge – rdurand

+0

Die perfekte Lösung mit Code und Erklärung: - http: //stackoverflow.com/a/32990248/98 8169 – pkc456

Antwort

12

Apple automatische Umsetzung der „Swipe rechts VC Pop“ funktioniert nur, für die linken ~ 20 Punkte des Bildschirms. Auf diese Weise stellen sie sicher, dass sie sich nicht mit den Funktionen Ihrer App herumschlagen. Stellen Sie sich vor, Sie haben einen UIScrollView auf dem Bildschirm, und Sie können nicht nach rechts wischen, weil VCs immer wieder herauskommen. Das wäre nicht nett.

Apple sagt here:

interactivePopGestureRecognizer

Die Gestenerkenner verantwortlich für die Top-View-Controller aus dem Navigationsstapel knallen. (Nur-Lese)

@property (nonatomic, nur lesbar) UIGestureRecognizer * interactivePopGestureRecognizer

Der Navigationsregler installiert diesen Gestenerkenner auf seiner Ansicht und verwendet sie die oberste Ansicht Regler aus dem Navigationsstapel Pop. Sie können diese Eigenschaft verwenden, um den Gestenerkenner abzurufen und ihn an das Verhalten anderer Gestenerkenner in Ihrer Benutzerschnittstelle zu binden. Wenn Sie Ihre Gestenerkenner zusammenbinden, stellen Sie sicher, dass sie ihre Gesten gleichzeitig erkennen, um sicherzustellen, dass Ihre Gestenerkenner eine Chance erhalten, das Ereignis zu behandeln.

So haben Sie Ihre eigenen UIGestureRecognizer, implementieren und ihr Verhalten auf die interactivePopGestureRecognizer Ihre UIViewController binden.


Edit:

Hier ist eine Lösung, die ich gebaut. Sie können Ihren eigenen Übergang implementieren, der dem Delegaten UIViewControllerAnimatedTransitioning entspricht. Diese Lösung funktioniert, wurde aber nicht gründlich getestet.

Sie einen interaktiven gleitenden Übergang erhalten Sie Ihre Viewcontrollers Pop. Sie können von überall in der Ansicht nach rechts rutschen.

Bekanntes Problem: Wenn Sie den Schwenk starten und vor der halben Breite der Ansicht anhalten, wird der Übergang abgebrochen (erwartetes Verhalten). Während dieses Vorgangs werden die Ansichten auf ihre ursprünglichen Frames zurückgesetzt. Sie sind ein visueller Fehler während dieser Animation.

Die Klassen des Beispiels sind die folgenden:

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 
+0

eine Idee Wie kann ich das tun? – chetu

+0

@chetu: Nein, Entschuldigung .. Ich werde Sie wissen lassen, wenn ich einen Weg finde, aber Ihre beste Option ist es, selbst zu versuchen. – rdurand

+0

@chetu: Ich habe eine funktionierende iOS7 + -Lösung – rdurand

5

Vererben die UINavigationController Sie UISwipeGestureRecognizer hinzufügen können die Pop-Aktion auslösen:

.h-Datei:

#import <UIKit/UIKit.h> 

@interface CNavigationController : UINavigationController 

@end 

.m-Datei:

#import "CNavigationController.h" 

@interface CNavigationController()<UIGestureRecognizerDelegate, UINavigationControllerDelegate> 

@property (nonatomic, retain) UISwipeGestureRecognizer *swipeGesture; 

@end 

@implementation CNavigationController 

#pragma mark - View cycles 

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    __weak CNavigationController *weakSelf = self; 
    self.delegate = weakSelf; 

    self.swipeGesture = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(gestureFired:)]; 
    [self.view addGestureRecognizer:self.swipeGesture]; } 

#pragma mark - gesture method 

-(void)gestureFired:(UISwipeGestureRecognizer *)gesture { 
    if (gesture.direction == UISwipeGestureRecognizerDirectionRight) 
    { 
     [self popViewControllerAnimated:YES]; 
    } } 

#pragma mark - UINavigation Controller delegate 

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated { 
    self.swipeGesture.enabled = NO; 
    [super pushViewController:viewController animated:animated]; } 

#pragma mark UINavigationControllerDelegate 

- (void)navigationController:(UINavigationController *)navigationController 
     didShowViewController:(UIViewController *)viewController 
        animated:(BOOL)animate { 
    self.swipeGesture.enabled = YES; } 

@end 
+0

Fügen Sie Ihren Code in Ihre Antwort ein. Wenn dein Link stirbt, ist deine Antwort nutzlos. – rdurand

+0

Diese Lösung verwendet einen Swipe, damit Sie keine Kontrolle über den Übergang erhalten. Es wird nicht interaktiv sein, während die Implementierung von Apple ist. – rdurand

+0

@drdurand ich muss ios6-Gerät unterstützen, das ist y ich habe das – Spynet

5

Hier ist eine Swift-Version von Spynet Antwort, mit einigen Modifikationen. Erstens habe ich eine lineare Kurve für die UIView Animation definiert. Zweitens habe ich der darunter liegenden Ansicht einen halbtransparenten schwarzen Hintergrund hinzugefügt, um einen besseren Effekt zu erzielen. Drittens habe ich eine UINavigationController subclassiert. Dadurch kann der Übergang auf jeden "Pop" -Übergang innerhalb des UINavigationControllers angewendet werden. Hier ist der Code:

CustomPopTransition.swift

import UIKit 

class CustomPopTransition: NSObject, UIViewControllerAnimatedTransitioning { 

    func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval { 
     return 0.3 
    } 

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { 
     guard let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from), 
       let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) 
     else { 
      return 
     } 

     let containerView = transitionContext.containerView 
     containerView.insertSubview(toViewController.view, belowSubview: fromViewController.view) 

     // Setup the initial view states 
     toViewController.view.frame = CGRect(x: -100, y: toViewController.view.frame.origin.y, width: fromViewController.view.frame.size.width, height: fromViewController.view.frame.size.height) 

     let dimmingView = UIView(frame: CGRect(x: 0,y: 0, width: toViewController.view.frame.width, height: toViewController.view.frame.height)) 
     dimmingView.backgroundColor = UIColor.black 
     dimmingView.alpha = 0.5 

     toViewController.view.addSubview(dimmingView) 

     UIView.animate(withDuration: transitionDuration(using: transitionContext), 
      delay: 0, 
      options: UIViewAnimationOptions.curveLinear, 
      animations: { 
       dimmingView.alpha = 0 
       toViewController.view.frame = transitionContext.finalFrame(for: toViewController) 
       fromViewController.view.frame = CGRect(x: toViewController.view.frame.size.width, y: fromViewController.view.frame.origin.y, width: fromViewController.view.frame.size.width, height: fromViewController.view.frame.size.height) 
      }, 
      completion: { finished in 
       dimmingView.removeFromSuperview() 
       transitionContext.completeTransition(!transitionContext.transitionWasCancelled) 
      } 
     ) 
    } 

} 

PoppingNavigationController.swift

import UIKit 

class PoppingNavigationController : UINavigationController, UINavigationControllerDelegate { 
    var interactivePopTransition: UIPercentDrivenInteractiveTransition! 

    override func viewDidLoad() { 
     self.delegate = self 
    } 

    func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) { 
     addPanGesture(viewController) 
    } 

    func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { 
     if (operation == .Pop) { 
      return CustomPopTransition() 
     } 
     else { 
      return nil 
     } 
    } 

    func navigationController(navigationController: UINavigationController, interactionControllerForAnimationController animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { 
     if animationController.isKindOfClass(CustomPopTransition) { 
      return interactivePopTransition 
     } 
     else { 
      return nil 
     } 
    } 

    func addPanGesture(viewController: UIViewController) { 
     let popRecognizer = UIPanGestureRecognizer(target: self, action: Selector("handlePanRecognizer:")) 
     viewController.view.addGestureRecognizer(popRecognizer) 
    } 

    func handlePanRecognizer(recognizer: UIPanGestureRecognizer) { 
     // Calculate how far the user has dragged across the view 
     var progress = recognizer.translationInView(self.view).x/self.view.bounds.size.width 
     progress = min(1, max(0, progress)) 
     if (recognizer.state == .Began) { 
      // Create a interactive transition and pop the view controller 
      self.interactivePopTransition = UIPercentDrivenInteractiveTransition() 
      self.popViewControllerAnimated(true) 
     } 
     else if (recognizer.state == .Changed) { 
      // Update the interactive transition's progress 
      interactivePopTransition.updateInteractiveTransition(progress) 
     } 
     else if (recognizer.state == .Ended || recognizer.state == .Cancelled) { 
      // Finish or cancel the interactive transition 
      if (progress > 0.5) { 
       interactivePopTransition.finishInteractiveTransition() 
      } 
      else { 
       interactivePopTransition.cancelInteractiveTransition() 
      } 
      interactivePopTransition = nil 
     } 
    } 
} 
+0

Wow !!! Danke Mann – Spynet

+1

@Spynet Kein Problem! Ich habe gerade den CustomPopTransition.swift-Code aktualisiert, weil ich einen Fehler mit dem anderen Code hier bemerkt habe, der mit dem passiert, was passiert, wenn Sie mehrere Male ziehen und wieder loslassen, bevor Sie das Zurückwischen begehen ... – Tometoyou

+0

Gut, weiter so – Spynet

0

Es gibt wirklich keine Notwendigkeit wollte, ist Ihre eigene Lösung für diese zu rollen, sub-Klassierung UINavigationController und Verweisen auf die Einbau-Geste funktioniert gut als here erklärt.

Die gleiche Lösung in Swift:

public final class MyNavigationController: UINavigationController { 

    public override func viewDidLoad() { 
    super.viewDidLoad() 


    self.view.addGestureRecognizer(self.fullScreenPanGestureRecognizer) 
    } 

    private lazy var fullScreenPanGestureRecognizer: UIPanGestureRecognizer = { 
    let gestureRecognizer = UIPanGestureRecognizer() 

    if let cachedInteractionController = self.value(forKey: "_cachedInteractionController") as? NSObject { 
     let string = "handleNavigationTransition:" 
     let selector = Selector(string) 
     if cachedInteractionController.responds(to: selector) { 
     gestureRecognizer.addTarget(cachedInteractionController, action: selector) 
     } 
    } 

    return gestureRecognizer 
    }() 
} 

Wenn Sie dies tun, auch die folgenden UINavigationControllerDelegate Funktion implementieren seltsames Verhalten an der Wurzel View-Controller zu vermeiden: sollte

public func navigationController(_: UINavigationController, 
           didShow _: UIViewController, animated _: Bool) { 
    self.fullScreenPanGestureRecognizer.isEnabled = self.viewControllers.count > 1 
} 
Verwandte Themen