我想在屏幕上向右滑动时弹出一个 View ,或者它像导航栏的后退按钮一样工作。
我正在使用:
self.navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self;
这行用于弹出导航 View 的代码对我来说很有效,但是当我从屏幕中间滑动时,它不会像 Instagram iPhone 应用程序那样工作。
这里我给出了 Instagram 应用程序的一个屏幕,您可以看到向右滑动弹出导航 View 的示例:
最佳答案
Apple 自动实现的“向右滑动弹出 VC”仅适用于屏幕左侧 ~20 点。通过这种方式,他们可以确保不会干扰您应用的功能。假设您在屏幕上有一个 UIScrollView
,并且您无法向右滑动,因为它会不断弹出 VC。这可不好。
Apple 说 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.
因此您必须实现自己的UIGestureRecognizer
,并将其行为绑定(bind)到您的UIViewController
的interactivePopGestureRecognizer
。
编辑:
这是我构建的解决方案。您可以根据 UIViewControllerAnimatedTransitioning
委托(delegate)实现自己的转换。此解决方案有效,但尚未经过全面测试。
您将获得一个交互式 滑动过渡来弹出您的 ViewController。您可以从 View 中的任何位置向右滑动。
已知问题:如果您开始平移并在 View 宽度的一半之前停止,过渡将被取消(预期行为)。在此过程中, View 将重置为其原始框架。这是此动画中的视觉故障。
示例的类如下:
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
关于ios - 像 Instagram iPhone 应用程序一样向右滑动时导航弹出 View 。我如何实现这一点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22244688/