navigation与手势的一些问题

1,349 阅读4分钟

navigation 简介

在使用 UINavigationController 的时候,系统的 navigationBar 不能满足多样化的设计要求,因此会定制 navigationItemtitleView或者完全自定义导航栏

顺便简单提一下导航自定义的一些内容

navigationbar自定义过程,标题自定义titleView使用自定义UIView

左右侧的组件是 navigationItem中的leftBarButtonItemleftBarButtonItemsrightBarButtonItemrightBarButtonItems,item里面的按钮使用的是UIBarButtonItem类型,相信大家已经很熟悉

如果都不满足,那么直接 setNavigationBarHidden:animated:方法隐藏导航栏,直接完全自定义

setHidesBottomBarWhenPushed:push时隐藏 tabbar的,不然 tabbar会一直显示

也有使用 UIViewControllerAnimatedTransitioning相关自定义 presentdimisspushpop动画的,总是非常多(后面一片文章会介绍自定义push等动画😂)

问题

1、系统的导航栏默认就那样,定制过程有限制,不能轻易使用非正常手段解决视觉效果,否则可能会出现下个版本更新效果消失甚至崩溃的问题

2、在自定义导航栏、隐藏导航栏、编写自定义跳转动画时,会出现系统默认的右滑手势失效问题

其中系统的右滑手势应该是使用UIScreenEdgePanGestureRecognizer实现的,从手机最左侧向右滑动可以退出当前页面

且只有非自定义导航栏的时候,且使用的是系统默认的 pushViewController:animated:方法进入,才会出现可以左滑退出的,因此此功能会令很多人头疼

3、系统默认的都是左滑进入上一页,如果当前页面不想左滑返回上一页怎么处理,可以设置当前页屏蔽左滑退出效果

解决方案

导航显示效果问题

如果使用默认的 titleViewnavigationItem不能解决问题,那么隐藏导航栏,完全自定义吧,毕竟有些看似巧妙的方法,有时解决方案不规范,会出现各种问题

右滑手势问题

创建一个子类继承自 UINavigationController,并实现 UIGestureRecognizerDelegate 协议

如果有些页面不想让它左滑返回上一页,可以在这里给其加入黑名单,屏蔽左侧右滑手势退出

如下所示,开启右滑退出


- (void)viewDidLoad {
    [super viewDidLoad];
    //系统的手势应该是 UIScreenEdgePanGestureRecognizer 类型
    if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
        self.interactivePopGestureRecognizer.delegate = self;
    }
//    [self setNavigationBarHidden:YES animated:YES]; //隐藏导航栏
//    [self setHidesBottomBarWhenPushed:YES]; //push隐藏tabbar
}

#pragma mark - UIGestureRecognizerDelegate
//这个方法是在手势将要激活前调用:返回YES允许右滑手势的激活,返回NO不允许右滑手势的激活
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    if (gestureRecognizer == self.interactivePopGestureRecognizer) {
        //屏蔽调用rootViewController的滑动返回手势,避免右滑返回手势引起死机问题
        //判断时,判断您当前控制器是否是跟控制器,注意有些符合controller会有多个子controller
        //如果有些页面不想让它左滑返回上一页,可以在这里给其加入黑名单判断,屏蔽左侧右滑手势退出
        if (self.viewControllers.count < 2 ||
            self.visibleViewController == [self.viewControllers objectAtIndex:0]) {
            return NO;
        }
    }
    //这里就是非右滑手势调用的方法啦,统一允许激活
    return YES;
}

手势协议(扩展)

上面虽然解决了侧滑问题,可是当界面中有滚动视图(scrollview)存在时,就会存在手势冲突问题,侧滑手势会失效,如果想解决可以尝试从 scrollview手势协议<UIGestureRecognizerDelegate>来入手

下面翻译一下方法使用,很容易理解,相信尝试一下很容易就解决了

@protocol UIGestureRecognizerDelegate <NSObject>

@optional

//开始进行手势识别时调用的方法,返回NO则结束识别,不再触发手势,用处:可以在控件指定的位置使用手势识别
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer;

//是否支持多手势触发,返回YES,则可以多个手势一起触发方法,返回NO则为互斥
//是否允许多个手势识别器共同识别,一个控件的手势识别后是否阻断手势识别继续向下传播,默认返回NO
//如果为YES,响应者链上层对象触发手势识别后,如果下层对象也添加了手势并成功识别也会继续执行
//否则上层对象识别后则不再继续传播
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
    shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;

//这个方法返回YES,第一个手势和第二个互斥时,第一个会失效
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer 
    shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer NS_AVAILABLE_IOS(7_0);

//这个方法返回YES,第一个和第二个互斥时,第二个会失效
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer 
    shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer NS_AVAILABLE_IOS(7_0);

//手指触摸屏幕后回调的方法,返回NO则不再进行手势识别,方法触发等
//此方法在window对象在有触摸事件发生时,调用gesture recognizer的touchesBegan:withEvent:方法之前调用
//如果返回NO,则gesture recognizer不会看到此触摸事件。(默认情况下为YES)
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer 
    shouldReceiveTouch:(UITouch *)touch;