IOS-FDFullscreenPopGesture的使用


https://www.jianshu.com/p/29e456ffa831

2017.12.25 20:39* 字数 484 阅读 2057评论 1

先贴上大神的blog 以示敬意 http://blog.sunnyxx.com/2015/06/07/fullscreen-pop-gesture/

改善后的demo地址   https://github.com/1570383140/FDFullscreenPopGesture

不得不说这真的是一个很牛逼的库。
首先这是一个对全局都能起作用的库,他有一些默认的操作。意思就是说你只要导入了就能够起作用。

默认起的作用就是全屏的返回手势

说真的,贼好用,对于大冬天不愿意拿出2只手但是屏幕又大的同学,真的是交互上的绝对性胜利。而且这个实现简直真的可以像大神说的 丝滑来形容。缘 妙不可言

导航栏的改变

以 A push B 作介绍

想要控制导航栏的显示或者隐藏,Apple对导航栏的API设计上总是不尽人意。
唉,UINavigationController和UIViewController总是2个不相同的控制器,并且他们的关系其实并没有达到谁控制谁。

如果需求是需要Apush后将B隐藏,我们在设置的时候一般会

  • 1、

     

    - (void)viewWillAppear:(BOOL)animated {

        [super viewWillAppear:animated];

        [self.navigationController setNavigationBarHidden:YES animated:YES];

    }

     

    - (void)viewWillDisappear:(BOOL)animated {

        [super viewWillDisappear:animated];

        [self.navigationController setNavigationBarHidden:NO animated:YES];

    }

     

     

    或者2、

     

    //要设置代理UINavigationControllerDelegate

    // 将要显示控制器

    - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {

        // 判断要显示的控制器是否是自己

        BOOL isShowHomePage = [viewController isKindOfClass:[self class]];

        [self.navigationController setNavigationBarHidden:isShowHomePage animated:YES];

    }

     

但是如果碰到丧心病狂的老板,他不要A也不要B,但是就要Push。

如果还按照以上写法,在用手势返回或者pop返回的时候,A界面会viewWillAppear执行。导致在滑动的过程中我们可以看到A界面导航栏的存在。这对强迫症来说完全不能忍,这时候FDFullscreenPopGesture就完全的解决了我们的问题。重要的是代码非常简洁,一句话。在所需要隐藏导航栏的界面写上

- (void)viewDidLoad

    [super viewDidLoad];

    self.navigationController.fd_prefersNavigationBarHidden = YES;

}

 

或者喜欢重载的写法也行:

- (BOOL)fd_prefersNavigationBarHidden {

    return YES;

}

 

解决FDFullscreenPopGesture连续多个页面隐藏导航栏的BUG

0.122018.01.02 23:18:50字数 413阅读 405

下面的方法可以用FDFullscreenPopGesture实现相邻页面的导航栏任意交替隐藏和显示(主要解决连续多个页面隐藏导航栏出现的BUG)

实现方法:

  • 在所有需要隐藏导航栏的页面加上如下代码
@property (nonatomic, assign) BOOL previousNaviBarShow; 
#import "UINavigationController+FDFullscreenPopGesture.h" - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; // 在所有需要隐藏导航栏的页面加上这两行代码,所有需要显示导航栏的页面不做任何操作即可 self.fd_prefersNavigationBarHidden = YES; [self.navigationController setNavigationBarHidden:YES animated:self.previousNaviBarShow]; } 
  • 在所有 由(显示导航栏页面)推出(隐藏导航栏页面)的地方,把要推出页面的previousNaviBarShow置为YES

   多个界面交替隐藏导航栏的    demo地址

注意,写了fd_prefersNavigationBarHidden就不能再去写关于viewWillAppear/viewWillDisappear/等一系列废操作了。因为这一句话已经囊括隐藏导航栏的代码了

 

 

 

使用FDFullscreenPopGesture遇到的坑以及解决方法

https://www.jianshu.com/p/bbc2305d83e2

最近需要给APP添加手势左滑返回功能,使用了框架FDFullscreenPopGesture,把使用过程中遇到的坑以及解决方法记录下

2018-05-03 更新------

当使用相机进行拍摄的时候,页面的上方看不见了,闪光灯功能使用不了,所以添加了如下判断:

    // 设置导航的显示/隐藏

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(CGFLOAT_MIN * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

        UIViewController *vc = [self.navigationController.viewControllers lastObject];

        // 添加对相机拍摄的过滤

        if ([self.navigationController isKindOfClass:[UIImagePickerController class]]

            ) {

            UIImagePickerController *imagePickVC = (UIImagePickerController *)self.navigationController;

            // 不是相机才进行处理

            if (imagePickVC.sourceType != UIImagePickerControllerSourceTypeCamera) {

                [self _handleVCNavigationBarHidden:vc];

            }

        } else {

            // 不是相机才进行处理

            [self _handleVCNavigationBarHidden:vc];

        }

    });

 

- (void)_handleVCNavigationBarHidden:(UIViewController *)vc {

    [self.navigationController setNavigationBarHidden:vc.fd_prefersNavigationBarHidden animated:NO];

}

 

一、UIWebView无法左滑返回

原因:UIWebView默认是不开启左滑手势返回功能的,需要自己开启;

解决:在viewDidLoad方法里面设置属性fd_interactivePopDisabled为NO;

- (void)viewDidLoad

{

    [super viewDidLoad];

    self.fd_interactivePopDisabled = NO;

}

 

二、UIWebView左滑返回没有成功时或者取消返回时导航栏的title文字为空,不见了

原因:在viewWillDisappear:方法里面UIWebView控件被销毁了;

ScanWebView = nil;

解决:

方法一: 最直接有效

在viewWillDisappear:方法里面取消UIWebView控件的销毁;即把这行代码注释掉;ScanWebView = nil;//注释掉

方法二: 比较复杂

在webViewDidFinishLoad:方法里面用一个变量保存获取的title文字,在viewWillAppear:方法里面设置导航栏的title文字;

1、保存title文字的变量

@property (nonatomic, copy) NSString *titleString; //保存title文字的变量

2、设置导航栏的title文字

- (void)viewWillAppear:(BOOL)animated{ //设置导航栏的title文字

    [super viewWillAppear:animated];

    self.titleLabel.text = self.titleString;

}

 

3、用变量保存获取到的title文字

- (void)webViewDidFinishLoad:(UIWebView *)webView{ //用变量保存获取到的title文字

    NSString *title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];

    self.titleString = title;

}

 

三、左滑返回没有成功或者取消时,会出现 ... 的情况

原因:导航控制器的导航栏默认是有一个返回按钮的;设置属性hidesBackButton为YES就会出现这种情况;

解决:设置属性hidesBackButton为NO,或者直接注释掉这行代码,不进行设置;

self.navigationItem.hidesBackButton = NO;

四、从无NavigationBar到有NavigationBar,手势返回的时候,有NavigationBar的控制器导航栏会变成白色,或者消失不见了;

原因:在滑动的时候显示出错

解决:

在viewWillAppear:和viewWillDisappear:方法里面添加对是否隐藏NavigationBar的判断;

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(CGFLOAT_MIN * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

    UIViewController *vc = [self.navigationController.viewControllers lastObject];

    if (vc.fd_prefersNavigationBarHidden) {

        [self.navigationController setNavigationBarHidden:YES animated:NO];

    } else {

        [self.navigationController setNavigationBarHidden:NO animated:NO];

    }

});

 

五、调用系统的发送短信控制器MFMessageComposeViewController时(如使用shareSDK进行短信分享时),右上角没有“取消按钮”,无法返回app

原因:好像被挡住了

解决:添加对控制器是否是MFMessageComposeViewController的判断,是的话添加自己添加一个取消按钮并添加方法的实现,

if ([self isKindOfClass:[MFMessageComposeViewController class]]) {

    [self fd_pushViewController:viewController animated:animated];

    [[self.viewControllers lastObject] navigationItem].rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(dismissModal:)];

    return;

}

 

- (void)dismissModal:(UIButton *)sender{

    [[self.viewControllers lastObject] dismissViewControllerAnimated:YES completion:nil];

}

 

以上为使用过程遇到的坑以及解决办法,很多也都是从GitHub搜集而来的,建议多到GitHub去看看;

附上FDFullscreenPopGesture的GitHub链接;https://github.com/forkingdog/FDFullscreenPopGesture

最后贴上在FDFullscreenPopGesture基础上修改后的代码:xx

 

// The MIT License (MIT)

//

// Copyright (c) 2015-2016 forkingdog ( https://github.com/forkingdog )

//

// Permission is hereby granted, free of charge, to any person obtaining a copy

// of this software and associated documentation files (the "Software"), to deal

// in the Software without restriction, including without limitation the rights

// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

// copies of the Software, and to permit persons to whom the Software is

// furnished to do so, subject to the following conditions:

//

// The above copyright notice and this permission notice shall be included in all

// copies or substantial portions of the Software.

//

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE

// SOFTWARE.

 

#import "UINavigationController+FDFullscreenPopGesture.h"

#import <objc/runtime.h>

#import <MessageUI/MessageUI.h>

 

@interface _FDFullscreenPopGestureRecognizerDelegate : NSObject <UIGestureRecognizerDelegate>

 

@property (nonatomic, weak) UINavigationController *navigationController;

 

@end

 

@implementation _FDFullscreenPopGestureRecognizerDelegate

 

- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer

{

    // Ignore when no view controller is pushed into the navigation stack.

    if (self.navigationController.viewControllers.count <= 1) {

        return NO;

    }

 

    // Ignore when the active view controller doesn't allow interactive pop.

    UIViewController *topViewController = self.navigationController.viewControllers.lastObject;

    if (topViewController.fd_interactivePopDisabled) {

        return NO;

    }

 

    // Ignore when the beginning location is beyond max allowed initial distance to left edge.

    CGPoint beginningLocation = [gestureRecognizer locationInView:gestureRecognizer.view];

    CGFloat maxAllowedInitialDistance = topViewController.fd_interactivePopMaxAllowedInitialDistanceToLeftEdge;

    if (maxAllowedInitialDistance > 0 && beginningLocation.x > maxAllowedInitialDistance) {

        return NO;

    }

 

    // Ignore pan gesture when the navigation controller is currently in transition.

    if ([[self.navigationController valueForKey:@"_isTransitioning"] boolValue]) {

        return NO;

    }

 

    // Prevent calling the handler when the gesture begins in an opposite direction.

    CGPoint translation = [gestureRecognizer translationInView:gestureRecognizer.view];

    if (translation.x <= 0) {

        return NO;

    }

 

    return YES;

}

 

@end

 

typedef void (^_FDViewControllerWillAppearInjectBlock)(UIViewController *viewController, BOOL animated);

 

@interface UIViewController (FDFullscreenPopGesturePrivate)

 

@property (nonatomic, copy) _FDViewControllerWillAppearInjectBlock fd_willAppearInjectBlock;

 

@end

 

@implementation UIViewController (FDFullscreenPopGesturePrivate)

 

+ (void)load

{

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        Class class = [self class];

 

        //viewWillAppear

        SEL originalSelector = @selector(viewWillAppear:);

        SEL swizzledSelector = @selector(fd_viewWillAppear:);

 

        Method originalMethod = class_getInstanceMethod(class, originalSelector);

        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

 

        BOOL success = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));

        if (success) {

            class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));

        } else {

            method_exchangeImplementations(originalMethod, swizzledMethod);

        }

 

        //viewWillDisappear

        SEL originalSelector2 = @selector(viewWillDisappear:);

        SEL swizzledSelector2 = @selector(fd_viewWillDisappear:);

 

        Method originalMethod2 = class_getInstanceMethod(class, originalSelector2);

        Method swizzledMethod2 = class_getInstanceMethod(class, swizzledSelector2);

 

        BOOL success2 = class_addMethod(class, originalSelector2, method_getImplementation(swizzledMethod2), method_getTypeEncoding(swizzledMethod2));

        if (success2) {

            class_replaceMethod(class, swizzledSelector2, method_getImplementation(originalMethod2), method_getTypeEncoding(originalMethod2));

        } else {

            method_exchangeImplementations(originalMethod2, swizzledMethod2);

        }

 

    });

}

 

- (void)fd_viewWillAppear:(BOOL)animated

{

    // Forward to primary implementation.

    [self fd_viewWillAppear:animated];

 

    if (self.fd_willAppearInjectBlock) {

        self.fd_willAppearInjectBlock(self, animated);

    }

 

    //设置导航的显示/隐藏

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(CGFLOAT_MIN * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

        UIViewController *vc = [self.navigationController.viewControllers lastObject];

        if (vc.fd_prefersNavigationBarHidden) {

            [self.navigationController setNavigationBarHidden:YES animated:NO];

        } else {

            [self.navigationController setNavigationBarHidden:NO animated:NO];

        }

    });

 

}

 

- (void)fd_viewWillDisappear:(BOOL)animated{

 

    [self fd_viewWillDisappear:animated];

 

    //设置导航的显示/隐藏

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(CGFLOAT_MIN * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

        UIViewController *vc = [self.navigationController.viewControllers lastObject];

        if (vc.fd_prefersNavigationBarHidden) {

            [self.navigationController setNavigationBarHidden:YES animated:NO];

        } else {

            [self.navigationController setNavigationBarHidden:NO animated:NO];

        }

    });

 

}

 

- (_FDViewControllerWillAppearInjectBlock)fd_willAppearInjectBlock

{

    return objc_getAssociatedObject(self, _cmd);

}

 

- (void)setFd_willAppearInjectBlock:(_FDViewControllerWillAppearInjectBlock)block

{

    objc_setAssociatedObject(self, @selector(fd_willAppearInjectBlock), block, OBJC_ASSOCIATION_COPY_NONATOMIC);

}

 

@end

 

@implementation UINavigationController (FDFullscreenPopGesture)

 

+ (void)load

{

    // Inject "-pushViewController:animated:"

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        Class class = [self class];

 

        SEL originalSelector = @selector(pushViewController:animated:);

        SEL swizzledSelector = @selector(fd_pushViewController:animated:);

 

        Method originalMethod = class_getInstanceMethod(class, originalSelector);

        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

 

        BOOL success = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));

        if (success) {

            class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));

        } else {

            method_exchangeImplementations(originalMethod, swizzledMethod);

        }

    });

}

 

- (void)fd_pushViewController:(UIViewController *)viewController animated:(BOOL)animated

{

    if (![self.interactivePopGestureRecognizer.view.gestureRecognizers containsObject:self.fd_fullscreenPopGestureRecognizer]) {

 

        // Add our own gesture recognizer to where the onboard screen edge pan gesture recognizer is attached to.

        [self.interactivePopGestureRecognizer.view addGestureRecognizer:self.fd_fullscreenPopGestureRecognizer];

 

        // Forward the gesture events to the private handler of the onboard gesture recognizer.

        NSArray *internalTargets = [self.interactivePopGestureRecognizer valueForKey:@"targets"];

        id internalTarget = [internalTargets.firstObject valueForKey:@"target"];

        SEL internalAction = NSSelectorFromString(@"handleNavigationTransition:");

        self.fd_fullscreenPopGestureRecognizer.delegate = self.fd_popGestureRecognizerDelegate;

        [self.fd_fullscreenPopGestureRecognizer addTarget:internalTarget action:internalAction];

 

        // Disable the onboard gesture recognizer.

        self.interactivePopGestureRecognizer.enabled = NO;

    }

 

    // Handle perferred navigation bar appearance.

    [self fd_setupViewControllerBasedNavigationBarAppearanceIfNeeded:viewController];

 

    //过滤MessageUI,并且添加取消按钮

    if ([self isKindOfClass:[MFMessageComposeViewController class]]) {

        [self fd_pushViewController:viewController animated:animated];

        [[self.viewControllers lastObject] navigationItem].rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(dismissModal:)];

        return;

    }

 

    // Forward to primary implementation.

    if (![self.viewControllers containsObject:viewController]) {

        [self fd_pushViewController:viewController animated:animated];

    }

 

}

 

- (void)dismissModal:(UIButton *)sender

{

    [[self.viewControllers lastObject] dismissViewControllerAnimated:YES completion:nil];

}

 

- (void)fd_setupViewControllerBasedNavigationBarAppearanceIfNeeded:(UIViewController *)appearingViewController

{

    if (!self.fd_viewControllerBasedNavigationBarAppearanceEnabled) {

        return;

    }

 

    __weak typeof(self) weakSelf = self;

    _FDViewControllerWillAppearInjectBlock block = ^(UIViewController *viewController, BOOL animated) {

        __strong typeof(weakSelf) strongSelf = weakSelf;

        if (strongSelf) {

            [strongSelf setNavigationBarHidden:viewController.fd_prefersNavigationBarHidden animated:animated];

        }

    };

 

    // Setup will appear inject block to appearing view controller.

    // Setup disappearing view controller as well, because not every view controller is added into

    // stack by pushing, maybe by "-setViewControllers:".

    appearingViewController.fd_willAppearInjectBlock = block;

    UIViewController *disappearingViewController = self.viewControllers.lastObject;

    if (disappearingViewController && !disappearingViewController.fd_willAppearInjectBlock) {

        disappearingViewController.fd_willAppearInjectBlock = block;

    }

}

 

- (_FDFullscreenPopGestureRecognizerDelegate *)fd_popGestureRecognizerDelegate

{

    _FDFullscreenPopGestureRecognizerDelegate *delegate = objc_getAssociatedObject(self, _cmd);

 

    if (!delegate) {

        delegate = [[_FDFullscreenPopGestureRecognizerDelegate alloc] init];

        delegate.navigationController = self;

 

        objc_setAssociatedObject(self, _cmd, delegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

    }

    return delegate;

}

 

- (UIPanGestureRecognizer *)fd_fullscreenPopGestureRecognizer

{

    UIPanGestureRecognizer *panGestureRecognizer = objc_getAssociatedObject(self, _cmd);

 

    if (!panGestureRecognizer) {

        panGestureRecognizer = [[UIPanGestureRecognizer alloc] init];

        panGestureRecognizer.maximumNumberOfTouches = 1;

 

        objc_setAssociatedObject(self, _cmd, panGestureRecognizer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

    }

    return panGestureRecognizer;

}

 

- (BOOL)fd_viewControllerBasedNavigationBarAppearanceEnabled

{

    NSNumber *number = objc_getAssociatedObject(self, _cmd);

    if (number) {

        return number.boolValue;

    }

    self.fd_viewControllerBasedNavigationBarAppearanceEnabled = YES;

    return YES;

}

 

- (void)setFd_viewControllerBasedNavigationBarAppearanceEnabled:(BOOL)enabled

{

    SEL key = @selector(fd_viewControllerBasedNavigationBarAppearanceEnabled);

    objc_setAssociatedObject(self, key, @(enabled), OBJC_ASSOCIATION_RETAIN_NONATOMIC);

}

 

@end

 

@implementation UIViewController (FDFullscreenPopGesture)

 

- (BOOL)fd_interactivePopDisabled

{

    return [objc_getAssociatedObject(self, _cmd) boolValue];

}

 

- (void)setFd_interactivePopDisabled:(BOOL)disabled

{

    objc_setAssociatedObject(self, @selector(fd_interactivePopDisabled), @(disabled), OBJC_ASSOCIATION_RETAIN_NONATOMIC);

}

 

- (BOOL)fd_prefersNavigationBarHidden

{

    return [objc_getAssociatedObject(self, _cmd) boolValue];

}

 

- (void)setFd_prefersNavigationBarHidden:(BOOL)hidden

{

    objc_setAssociatedObject(self, @selector(fd_prefersNavigationBarHidden), @(hidden), OBJC_ASSOCIATION_RETAIN_NONATOMIC);

}

 

 

- (CGFloat)fd_interactivePopMaxAllowedInitialDistanceToLeftEdge

{

#if CGFLOAT_IS_DOUBLE

    return [objc_getAssociatedObject(self, _cmd) doubleValue];

#else

    return [objc_getAssociatedObject(self, _cmd) floatValue];

#endif

}

 

- (void)setFd_interactivePopMaxAllowedInitialDistanceToLeftEdge:(CGFloat)distance

{

    SEL key = @selector(fd_interactivePopMaxAllowedInitialDistanceToLeftEdge);

    objc_setAssociatedObject(self, key, @(MAX(0, distance)), OBJC_ASSOCIATION_RETAIN_NONATOMIC);

}

 

@end

最后贴上改善后的GitHub地址  https://github.com/1570383140/FDFullscreenPopGesture.git

作者:zhhelnice 

来源:CSDN 

原文:https://blog.csdn.net/zhhelnice/article/details/60580637 

 

作者:oceanfive

链接:https://www.jianshu.com/p/bbc2305d83e2

来源:简书

简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM