11 ios 导航按钮失效_ios uitableviewcell 按钮失效 - CSDN
  • iOS11 导航按钮位置问题的解决此文是iOS11在beta的时候写的,当时主要是为了解决问题,并没有想太多的优化,后期发现其代码量比较大,且会出现一些问题,比如多个按钮的设置,比如约束的丢失等,现在换了新的思路去实现新...

    iOS11 导航栏按钮位置问题的解决

    此文是iOS11在beta的时候写的,当时主要是为了解决问题,并没有想太多的优化,后期发现其代码量比较大,且会出现一些问题,比如多个按钮的设置,比如约束的丢失等,现在换了新的思路去实现

    新的解决方案
    iOS11 导航栏按钮位置问题的解决——新
    http://blog.csdn.net/spicyShrimp/article/details/78201042

    当然此文仍然可以作为解决方案来实施.
    虽然现在iOS11正式版还没有出来,但是作为开发人员,相信很多开发者都在使用xcode beta进行着调试,防止iOS 11出来的时候,对现有的应用的不兼容造成问题无法及时解决,我也是这么做的.
    不得不说iOS 11的改动相当的大,表格中的estimatedRowHeight,导航栏大标题,安全区域….
    当然这里不是我要说的东西.
    作为一个开发者,第一时间适配新的SDK或者开发框架,这是最起码的要求,当然如果在beta版的时候就能做好兼容,这是再好不过的了.

    废话不多说了.
    作为一个iOS开发者,大家都知道开发中经常遇到问题的不是某一个界面,不是某一个功能,相反的,而是我们经常不在乎的导航栏.原因很简单.

    • 系统自动管理
    • 高度封装,修改难度大
    • 图层多,很多自己用不到的图层穿插其中,造成开发效果的影响

    大致的举个例子,我们设置NavigationBar的背景色,我们设置UIBarButtonItem的位置偏移问题等等,
    当然,这些都是大家早就研究过的,解决方案也有很多

    • 无非是完全自定义导航栏,不适用系统的NavigationBar
    • 直接或者间接的修改系统的NavigationBar 或者 UIBarButtonItem等

    这里我就说说导航栏按钮的位置问题

    在iOS7之后,我们在设置UINavigationItem的leftBarButtonItem,rightBarButtonItem的时候都会造成位置的偏移,虽然不大,但是跟UI的设计或者国人的习惯有点区别.当然也有很好的解决方案,多添加一个消极的宽度为负值的UIBarButtonItem

    +(UIBarButtonItem *)fixedSpaceWithWidth:(CGFloat)width {
    
        UIBarButtonItem *fixedSpace = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
        fixedSpace.width = width;
        return fixedSpace;
    }

    在我们添加导航栏按钮的时候
    我们使用就可以满足将按钮位置调整的需求

    [self.navigationItem setRightBarButtonItems:@[[UIBarButtonItem fixedSpaceWithWidth:-20], rightBarButtonItem]];

    但是这些在iOS 11中都无效了!!!!
    但是这些在iOS 11中都无效了!!!!
    但是这些在iOS 11中都无效了!!!!

    重要的事情说3遍.

    iOS 11改动相当大的就是导航栏的部分,在原来的已经复杂的不要的图层中又新增了新的图层!

    这里写图片描述

    这里写图片描述

    是的你没有看做,_UINavigationBarContentView和_UIButtonBarStackView和_UITAMICAdaptorView
    而我们之前的leftBarButtonItem什么的现在都在UIButtonBarStackView中了.更无语的是这些

    <_UIButtonBarStackView: 0x7ff988074290; frame = (12 0; 48 44); layer = <CALayer: 0x60000042bc80>>
    Printing description of $11:
    <UIView: 0x7ff9880764a0; frame = (0 22; 8 0); layer = <CALayer: 0x60000042b7c0>>
    Printing description of $12:
    <_UITAMICAdaptorView: 0x7ff988076790; frame = (8 2; 40 40); autoresizesSubviews = NO; layer = <CALayer: 0x60000042b8a0>>

    我们可以看到一个_UIButtonBarStackView占掉了12个像素的左边约束,_UITAMICAdaptorView又占据了8个像素的左边约束,所以说我们很无语的就被占据了20px,更可气的是,都是私有对象,不容易修改!

    于是还是老套路,我们设置负值来调整约束,结果却失败了,无效…
    迫于无奈,我们只能想新的办法,

    • 放弃UIBarButtonItem,放弃UINavigationBar,使用自定义视图代替
    • 在UINavigationBar中使用添加视图的方式,固定位置固定大小添加按钮
    • UIBarButtonItem.customView 设置偏移(比如按钮设置图片偏移 视图设置tranform等)
    • 修改UIBarButtonItem图层结构(删除图层,或者修改约束)

    当然,完全的使用自定义视图代替原生的UINavigationBar和UIBarButtonItem,这里我也不需要说明了.就是自定义视图蛮,肯定都能解决

    使用addSubview:添加,之后remove什么的虽然可以,但是这个也不是我想要的

    至于这是偏移,结果也嗯惨淡,无效.我尝试了设置旋转都可以,但是设置位置左移就失效了.很无语

    为什么非要大动代码呢?在iOS 11之前,我们的项目绝大部分都是使用UINavigationBar和UIBarButtonItem,也就是系统的来管理,现在如果因为一个偏移问题,我们就要修改过多代码,岂不是很麻烦?
    能否有较小代价实现?
    答案是有的,

    我们可能会做这样的一个分类

    @implementation UINavigationItem (SXFixSpace)
    
    +(void)load {
        [self swizzleInstanceMethodWithOriginSel:@selector(setLeftBarButtonItem:)
                                     swizzledSel:@selector(sx_setLeftBarButtonItem:)];
        [self swizzleInstanceMethodWithOriginSel:@selector(setRightBarButtonItem:)
                                     swizzledSel:@selector(sx_setRightBarButtonItem:)];
    }
    
    -(void)sx_setLeftBarButtonItem:(UIBarButtonItem *)leftBarButtonItem{
        if (leftBarButtonItem.customView) {
            [self sx_setLeftBarButtonItem:nil];
            [self setLeftBarButtonItems:@[[UIBarButtonItem fixedSpaceWithWidth:-20], leftBarButtonItem]];
        }else {
            [self setLeftBarButtonItems:nil];
            [self sx_setLeftBarButtonItem:leftBarButtonItem];
        }
    }
    
    -(void)sx_setRightBarButtonItem:(UIBarButtonItem *)rightBarButtonItem{
        if (rightBarButtonItem.customView) {
            [self sx_setRightBarButtonItem:nil];
            [self setRightBarButtonItems:@[[UIBarButtonItem fixedSpaceWithWidth:-20], rightBarButtonItem]];
        }else {
            [self setRightBarButtonItems:nil];
            [self sx_setRightBarButtonItem:rightBarButtonItem];
        }
    }
    @end

    在我们iOS11之前,我们使用这样的一个分类来扩展,
    使得我们在vc中就能这样使用

    self.navigationItem.leftBarButtonItem = [UIBarButtonItem itemWithTarget:self action:@selector(sx_pressBack:) image:[UIImage imageNamed:@"nav_back"]];

    就能调整好我们的按钮位置

    那么能不能不懂这些代码也满足iOS 11呢?

    那么只有在加一点点东西了,在分类中

    -(void)sx_setLeftBarButtonItem:(UIBarButtonItem *)leftBarButtonItem{
        if (leftBarButtonItem.customView) {
            if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 11) {
                //如果调整,在这里实现,这样就能达到不影响代码的效果
            }else {
                [self sx_setLeftBarButtonItem:nil];
                [self setLeftBarButtonItems:@[[UIBarButtonItem fixedSpaceWithWidth:-20], leftBarButtonItem]];
            }
        }else {
            [self setLeftBarButtonItems:nil];
            [self sx_setLeftBarButtonItem:leftBarButtonItem];
        }
    }

    在什么地方写我们都能想明白,接下来是怎么写的问题了
    我的思路是既然他是一个customView,那么我能否扩展这个customView呢?
    我们原来将一个按钮直接用作customView,比如这样

    [[UIBarButtonItem alloc] initWithCustomView:button];

    但是现在我想的是按钮添加在一个我们定义的view中,view作为customView
    这样view作为一个位置调整的视图,就可以相对自由的定义了

    -(void)sx_setLeftBarButtonItem:(UIBarButtonItem *)leftBarButtonItem{
        if (leftBarButtonItem.customView) {
            if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 11) {
                UIView *customView = leftBarButtonItem.customView;
                BarView *barView = [[BarView alloc]initWithFrame:customView.bounds];
                [barView addSubview:customView];
                customView.center = barView.center;
                [barView setPosition:SXBarViewPositionLeft];//说明这个view需要调整的是左边
                [self setLeftBarButtonItems:nil];
                [self sx_setLeftBarButtonItem:[[UIBarButtonItem alloc]initWithCustomView:barView]];
            }else {
                [self sx_setLeftBarButtonItem:nil];
                [self setLeftBarButtonItems:@[[UIBarButtonItem fixedSpaceWithWidth:-20], leftBarButtonItem]];
            }
        }else {
            [self setLeftBarButtonItems:nil];
            [self sx_setLeftBarButtonItem:leftBarButtonItem];
        }
    }

    那么这个view我们也能干些事情了

    typedef NS_ENUM(NSInteger, SXBarViewPosition) {
        SXBarViewPositionLeft,
        SXBarViewPositionRight
    };
    
    @interface BarView : UIView
    @property (nonatomic, assign) SXBarViewPosition position;
    @property (nonatomic, assign) BOOL applied;
    @end
    
    @implementation BarView
    
    - (void)layoutSubviews {
        [super layoutSubviews];
        if (self.applied || [[[UIDevice currentDevice] systemVersion] floatValue]  < 11) return;
        UIView *view = self;
        while (![view isKindOfClass:UINavigationBar.class] && view.superview) {
            view = [view superview];
            if ([view isKindOfClass:UIStackView.class] && view.superview) {
                if (self.position == SXBarViewPositionLeft) {
                    for (NSLayoutConstraint *constraint in view.superview.constraints) {
                        if ([constraint.firstItem isKindOfClass:[UILayoutGuide class]] &&
                         constraint.firstAttribute == NSLayoutAttributeTrailing) {
                            [view.superview removeConstraint:constraint];
                        }
                    }
                    [view.superview addConstraint:[NSLayoutConstraint constraintWithItem:view
                                                                               attribute:NSLayoutAttributeLeading
                                                                               relatedBy:NSLayoutRelationEqual
                                                                                  toItem:view.superview
                                                                               attribute:NSLayoutAttributeLeading
                                                                              multiplier:1.0
                                                                                constant:0]];
                    self.applied = YES;
                } else if (self.position == SXBarViewPositionRight) {
                    for (NSLayoutConstraint *constraint in view.superview.constraints) {
                        if ([constraint.firstItem isKindOfClass:[UILayoutGuide class]] &&
                         constraint.firstAttribute == NSLayoutAttributeLeading) {
                            [view.superview removeConstraint:constraint];
                        }
                    }
                    [view.superview addConstraint:[NSLayoutConstraint constraintWithItem:view
                                                                               attribute:NSLayoutAttributeTrailing
                                                                               relatedBy:NSLayoutRelationEqual
                                                                                  toItem:view.superview
                                                                               attribute:NSLayoutAttributeTrailing
                                                                              multiplier:1.0
                                                                                constant:0]];
                    self.applied = YES;
                }
                break;
            }
        }
    }
    
    @end

    代码其实不复杂,就是遍历view的父视图,当其实UIStackView的时候,我们修改其左右约束,但是仅仅修改的话会造成约束冲突,所以我们还需要提前移除约束冲突的左右约束(如果担心影响问题,不移除没有关系,仅仅是编译器会报约束冲突log,代码洁癖的话会感觉不舒服)

    于是在原来的分类中稍作扩展,我们的新的分类就完成了

    #import "UINavigationItem+SXFixSpace.h"
    #import "NSObject+SXRuntime.h"
    #import <UIKit/UIKit.h>
    
    typedef NS_ENUM(NSInteger, SXBarViewPosition) {
        SXBarViewPositionLeft,
        SXBarViewPositionRight
    };
    
    @interface BarView : UIView
    @property (nonatomic, assign) SXBarViewPosition position;
    @property (nonatomic, assign) BOOL applied;
    @end
    
    @implementation BarView
    
    - (void)layoutSubviews {
        [super layoutSubviews];
        if (self.applied || [[[UIDevice currentDevice] systemVersion] floatValue]  < 11) return;
        UIView *view = self;
        while (![view isKindOfClass:UINavigationBar.class] && view.superview) {
            view = [view superview];
            if ([view isKindOfClass:UIStackView.class] && view.superview) {
                if (self.position == SXBarViewPositionLeft) {
                    for (NSLayoutConstraint *constraint in view.superview.constraints) {
                        if ([constraint.firstItem isKindOfClass:[UILayoutGuide class]] && 
                        constraint.firstAttribute == NSLayoutAttributeTrailing) {
                            [view.superview removeConstraint:constraint];
                        }
                    }
                    [view.superview addConstraint:[NSLayoutConstraint constraintWithItem:view
                                                                               attribute:NSLayoutAttributeLeading
                                                                               relatedBy:NSLayoutRelationEqual
                                                                                  toItem:view.superview
                                                                               attribute:NSLayoutAttributeLeading
                                                                              multiplier:1.0
                                                                                constant:0]];
                    self.applied = YES;
                } else if (self.position == SXBarViewPositionRight) {
                    for (NSLayoutConstraint *constraint in view.superview.constraints) {
                        if ([constraint.firstItem isKindOfClass:[UILayoutGuide class]] && 
                        constraint.firstAttribute == NSLayoutAttributeLeading) {
                            [view.superview removeConstraint:constraint];
                        }
                    }
                    [view.superview addConstraint:[NSLayoutConstraint constraintWithItem:view
                                                                               attribute:NSLayoutAttributeTrailing
                                                                               relatedBy:NSLayoutRelationEqual
                                                                                  toItem:view.superview
                                                                               attribute:NSLayoutAttributeTrailing
                                                                              multiplier:1.0
                                                                                constant:0]];
                    self.applied = YES;
                }
                break;
            }
        }
    }
    
    @end
    
    @implementation UINavigationItem (SXFixSpace)
    
    +(void)load {
        [self swizzleInstanceMethodWithOriginSel:@selector(setLeftBarButtonItem:)
                                     swizzledSel:@selector(sx_setLeftBarButtonItem:)];
        [self swizzleInstanceMethodWithOriginSel:@selector(setRightBarButtonItem:)
                                     swizzledSel:@selector(sx_setRightBarButtonItem:)];
    }
    
    -(void)sx_setLeftBarButtonItem:(UIBarButtonItem *)leftBarButtonItem{
        if (leftBarButtonItem.customView) {
            if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 11) {
                UIView *customView = leftBarButtonItem.customView;
                BarView *barView = [[BarView alloc]initWithFrame:customView.bounds];
                [barView addSubview:customView];
                customView.center = barView.center;
                [barView setPosition:SXBarViewPositionLeft];
                [self setLeftBarButtonItems:nil];
                [self sx_setLeftBarButtonItem:[[UIBarButtonItem alloc]initWithCustomView:barView]];
            }else {
                [self sx_setLeftBarButtonItem:nil];
                [self setLeftBarButtonItems:@[[UIBarButtonItem fixedSpaceWithWidth:-20], leftBarButtonItem]];
            }
        }else {
            [self setLeftBarButtonItems:nil];
            [self sx_setLeftBarButtonItem:leftBarButtonItem];
        }
    }
    
    -(void)sx_setRightBarButtonItem:(UIBarButtonItem *)rightBarButtonItem{
        if (rightBarButtonItem.customView) {
            if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 11) {
                UIView *customView = rightBarButtonItem.customView;
                BarView *barView = [[BarView alloc]initWithFrame:customView.bounds];
                [barView addSubview:customView];
                customView.center = barView.center;
                [barView setPosition:SXBarViewPositionRight];
                [self setRightBarButtonItems:nil];
                [self sx_setRightBarButtonItem:[[UIBarButtonItem alloc]initWithCustomView:barView]];
            } else {
                [self sx_setRightBarButtonItem:nil];
                [self setRightBarButtonItems:@[[UIBarButtonItem fixedSpaceWithWidth:-20], rightBarButtonItem]];
            }
        }else {
            [self setRightBarButtonItems:nil];
            [self sx_setRightBarButtonItem:rightBarButtonItem];
        }
    }
    
    @end

    使用前
    这里写图片描述
    这里写图片描述

    使用后
    这里写图片描述
    这里写图片描述

    我不需要需改任何界面上的代码,在iOS 11下解决了导航栏按钮位置问题
    当然你也能在做扩展,是偏移多少,修改约束的值即可
    上面部分代码省略,完整demo请移步下载

    另外,鉴于很多人在使用时发现的问题,我这里也统一解决一下
    因为此方案只是临时的折中方案,不可能完美,
    所以在使用的时候会发现这些问题

    1.某一个界面在push一个新界面之后再返回回来之后位置就还原了
    解决方案其实很简单,只要将设置leftItem的方法写在viewWillAppear中即可,这样即可保证约束不会被系统重置

    2.引用文件却仍找不到方法,运行崩溃
    解决方案1:
    这个是个案,一般是不会发生这个情况的,出现这些情况的项目,只要在target->build setting->other link flags中手动添加文件路径即可,这个是xcode的一个bug,跟代码无关
    解决方案2:
    找到xcode无法识别的.m文件
    这里写图片描述
    勾选右侧的target membership
    目前看来这个是xcode9的一个bug
    跟项目本身无关

    3.删除约束的判断是否有效
    demo中的删除约束的判断仅仅是我个人项目中的判断,每个开发者的项目因为各种因素可能会有不同的影响,大家可以根据项目自行判断需要删除的约束条件,亦或者是不删除约束也是可以的

    demo地址
    https://github.com/spicyShrimp/iOS-11-UINavigationItem-SXFixSpace

    此外,如果大家有更好的方案或者解决思路,欢迎一起探讨

    展开全文
  • iOS导航栏的按钮处理

    2016-05-26 13:01:10
    侧滑返回手势是从iOS7开始增加的一个返回操作,经历了两年时间估计iPhone用户大部分都已经忽略了屏幕左上角那个碍眼的按钮了。之前在网上搜过有关侧滑手势的技术博客,发现大多比较散乱,甚至有很多都是简单的粘贴...


    转自:http://www.jianshu.com/p/e7c5e2400935


    前言(其实就是废话,可以忽略 = =)

    侧滑返回手势是从iOS7开始增加的一个返回操作,经历了两年时间估计iPhone用户大部分都已经忽略了屏幕左上角那个碍眼的按钮了。之前在网上搜过有关侧滑手势的技术博客,发现大多比较散乱,甚至有很多都是简单的粘贴复制,并不全面。在这里写这篇文章的目地,就是希望比较系统把侧滑手势的相关内容做下总结,也希望可以帮助到正在找相关资料的同学。(不知不觉iOS系统版本都已经更新到9了,想想最初还在纠结iOS6和iOS7适配问题,不禁感觉到时间过的飞快。)

    正文

    侧滑手势在应用的实际场景中应该分为两种情况

    • 使用系统自带的返回按钮
    • 使用自定义的返回按钮

    那么在项目中我们会对侧滑手势做哪些自定义的操作呢?下面是我自己总结的几个常用的操作

    • 禁用/启用侧滑手势
    • 获取侧滑手势

    好了,下面我们开始进入正题。

    先创建一个继承自 UINavigationController 的子类,然后让我们来看一下 UINavigationController@property ,可以找到下面这个属性:
    @property(nullable, nonatomic, readonly) UIGestureRecognizer *interactivePopGestureRecognizer
    这个属性就是我们的侧滑返回手势,如果你的项目中没有需求要自定义返回按钮(虽然我觉得这并不太可能),那么你所需要的操作就非常简单了,不多说直接上代码。

    self.navigationController.interactivePopGestureRecognizer.enabled = YES;   //启用侧滑手势
    self.navigationController.interactivePopGestureRecognizer.enabled = NO;   //禁用侧滑手势

    如果你需要自定义返回按钮的话,我这有两套方案供您选择

    1、用自定义的 UIBarButtonItem 替换 navigationController backBarButtonItem 记住是 backBarButtonItem 而不是 leftBarButtonItem ,如果你不小心替换成了 leftBarButtonItem ,那么会直接导致侧滑手势失效。有关 backBarButtonItemleftBarButtonItem的区别可以参考这篇文章

    • 优点:比较简单,不需要重新设置侧滑手势的代理自己管理;
    • 缺点:只适用于左上角只有一个返回按钮的需求;
    UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom]; 
    //对按钮的个性化设定
    
    UIBarButtonItem *barItem = [[UIBarButtonItem alloc] initWithCustomView:backButton]; 
    self.navigationItem.leftBarButtonItem = barItem; //侧滑手势失效
    self.navigationItem.backBarButtonItem = barItem; //不影响侧滑手势

    2、刚才说到 1 的方法只适用于左上角只有一个返回按钮的情况,那么当我们需要用到多个按钮的时候该怎么做呢?这个时候就到了方案 2 上场的时候啦!那就是重新设置侧滑手势的代理,并手动管理。上面我们已经创建了一个 UINavigationController 的子类,这里我们姑且称BSDemoNavigationController,下面直接看代码,在代码中讲解。

    //首先先让我们自定义的 UINavigationController 遵守几个协议
    @interface BSDemoNavigationController ()<UINavigationControllerDelegate,UIGestureRecognizerDelegate,BSNavigationBarButtonActionDelegate>
    
    @property(nonatomic,weak) UIViewController* currentShowVC;
    
    @end
    
    @implementation BSDemoNavigationController
    
    -(id)initWithRootViewController:(UIViewController *)rootViewController
    {
        //覆盖创建
        BSDemoNavigationController* nvc = [super initWithRootViewController:rootViewController];
        nav.interactivePopGestureRecognizer.delegate = self;
        nvc.delegate = self;
        return nvc;
    }
    
    #pragma mark - UIGestureRecognizerDelegate
    //这个方法在视图控制器完成push的时候调用
    -(void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
    {
        if (navigationController.viewControllers.count == 1){ 
            //如果堆栈内的视图控制器数量为1 说明只有根控制器,将currentShowVC 清空,为了下面的方法禁用侧滑手势
            self.currentShowVC = Nil;
        }
        else{ 
            //将push进来的视图控制器赋值给currentShowVC
            self.currentShowVC = viewController;
        }
    }
    //这个方法是在手势将要激活前调用:返回YES允许侧滑手势的激活,返回NO不允许侧滑手势的激活
    - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
    {
        //首先在这确定是不是我们需要管理的侧滑返回手势
        if (gestureRecognizer == self.interactivePopGestureRecognizer) {
            if (self.currentShowVC == self.topViewController) {
                //如果 currentShowVC 存在说明堆栈内的控制器数量大于 1 ,允许激活侧滑手势
                return YES;
            }
            //如果 currentShowVC 不存在,禁用侧滑手势。如果在根控制器中不禁用侧滑手势,而且不小心触发了侧滑手势,会导致存放控制器的堆栈混乱,直接的效果就是你发现你的应用假死了,点哪都没反应,感兴趣是神马效果的朋友可以自己试试 = =。
            return NO;
        }
    
        //这里就是非侧滑手势调用的方法啦,统一允许激活
        return YES;
    }

    好了,进行到这里即使我们自定义了 UINavigationController 的返回按钮,侧滑手势也应该可以正常使用了。但是大家不要高兴的太早,这么做完之后如果你的界面中没有 scrollView 的话确实能过一切顺利,反过说就是控制器中有 scrollView 存在,且你的 scrollView 又正好处在触发侧滑手势的屏幕边缘的话(比如全屏幕的 UITabelView ,和屏幕等宽的用来展示广告的 UIScrollView ),这些 scrollView 会随着你的侧滑返回手势一起滑动,至于效果图就让本喵偷下懒吧 = =。

    废话就不多说了,让我们来做最后的优化吧,毕竟谁不想让自己的应用尽善尽美呢!

    先说下思路吧,我们既然不想同时响应侧滑和 scrollView 的滑动事件,那么我要要做的就是让 scrollView 在侧滑手势判定为失败后再响应滚动事件。

    首先还是在我们自定义的BSDemoNavigationController 中加入如下代码。

    //获取侧滑返回手势
    - (UIScreenEdgePanGestureRecognizer *)screenEdgePanGestureRecognizer
    {
        UIScreenEdgePanGestureRecognizer *screenEdgePanGestureRecognizer = nil;
        if (self.view.gestureRecognizers.count > 0)
        {
            for (UIGestureRecognizer *recognizer in self.view.gestureRecognizers)
            {
                if ([recognizer isKindOfClass:[UIScreenEdgePanGestureRecognizer class]])
                {
                    screenEdgePanGestureRecognizer = (UIScreenEdgePanGestureRecognizer *)recognizer;
                    break;
                }
            }
        }
        return screenEdgePanGestureRecognizer;
    }

    然后在需要优化的控制中取得我们 BSDemoNavigationController 的实例对象,如何取得方法很多,self.navigationController、单例、appDelegate 等都可以,就不一一赘述了,这里我使用的是 在控制器中使用self.navigationController 获得。

    //禁止侧滑手势和tableView同时滑动
    BSDemoNavigationController *navController = (BSDemoNavigationController *)self.navigationController;
    if ([navController screenEdgePanGestureRecognizer]) {
        //指定滑动手势在侧滑返回手势失效后响应
        [self.friendsDemoTableView.panGestureRecognizer requireGestureRecognizerToFail:[navController screenEdgePanGestureRecognizer]];
    }

    好了到这为止、我们的侧滑返回也就大功告成了,文章到这里也就到一段落了。如果你有什么问题欢迎在下面评论提出,如果你有什么更好的解决办法也希望能够跟大家一起共享。最后如果你觉得我的文章对你还有点帮助的话就请点下下面的爱心支持我下吧 !


    更新

    针对直接使用 backBarButtonItem 前面直接略过可能会导致某些同学造成误解,在此更新一下并说明简单说明一下 backBarButtonItem 的用法。

    一、理解误区

    误区一:分不清backBarButtonItembackIndicatorImage
    有些同学误解了 backBarButtonItembackIndicatorImage,所以在设置的时候就会存在一些困惑。下面我们来看张图:


    区分 backBarButtonItem 和 backIndicatorImage

    看到这张图片部分同学就可以理解了针对不同的需求应该去修改什么属性。在这里我也说明一下在哪里设置这两个属性。

    • backIndicatorImage: 是 navigationBar 的属性,一般有需求替换返回图片的需求时在创建 navigationController 时设置一次即可。
    • backBarButtonItem : 是 navigationItem 的属性,一般有自定义返回按钮文字的需求时在 viewController 中设置

    误区二:不知道在哪儿设置backBarButtonItem
    大部分做过 iOS 开发的同学应该都使用过 leftBarButtonItemrightBarButtonItem (自定义这两个空间的方法就不在赘述,Google / Baidu 随便搜下都能出来相关的方法),所以有些同学可能想当然的理解为设置 backBarButtonItem 也是在同样的地方设置即可。正确的理解如下:

    when A -> B : 此时处于 B 控制器 ,导航栏上显示的 backBarButtonItem 显示的为 A 控制器的 backBarButtonItem 。如图


    a.png


    所以当你要 B 控制器导航栏上的返回按钮时,你需要去修改 A 的 backBarButtonItem

    二、情景实战

    情景一:自定义 backBarButtonItem 文字
    在 A 控制器的 - (void)viewDidLoad 中加入如下方法

    - (void)viewDidLoad {
        [super viewDidLoad];
        self.view.backgroundColor = [UIColor whiteColor];
        self.navigationItem.title = @"Fir Controller";
        self.navigationItem.leftItemsSupplementBackButton = YES;
    
        UIButton  *button = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
        [button setTitle:@"下一层" forState:UIControlStateNormal];
        [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        [button addTarget:self action:@selector(pushAction:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:button];
    
    
    
        UIBarButtonItem *backItem = [[UIBarButtonItem alloc]init];
        backItem.title = @"A的BackButtonItem";
        self.navigationItem.backBarButtonItem = backItem;
    }

    运行结果如下:


    A 改.png

    情景二:自定义返回图片并隐藏标题
    自定义一个 navigationController 并在- (void)viewDidLoad中加入如下方法

    #import "CustomNavigationController.h"
    
    @implementation CustomNavigationController
    
    - (instancetype)initWithRootViewController:(UIViewController *)rootViewController {
        if (self = [super initWithRootViewController:rootViewController]) {
            UIImage *image = [UIImage imageNamed:@"JWDemo_Back"];
            image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
            self.navigationBar.backIndicatorImage = image;
            self.navigationBar.backIndicatorTransitionMaskImage = image;
        }
        return self;
    }
    @end

    并在 A 控制器的 - (void)viewDidLoad 中加入如下方法

    - (void)viewDidLoad {
        [super viewDidLoad];
        self.view.backgroundColor = [UIColor whiteColor];
        self.navigationItem.title = @"Fir Controller";
        self.navigationItem.leftItemsSupplementBackButton = YES;
    
        UIButton  *button = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
        [button setTitle:@"下一层" forState:UIControlStateNormal];
        [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        [button addTarget:self action:@selector(pushAction:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:button];
    
    
    
        UIBarButtonItem *backItem = [[UIBarButtonItem alloc]init];
        backItem.title = @"";
        self.navigationItem.backBarButtonItem = backItem;
    }

    运行结果如下


    自定义图片.png

    好了,大家可以自己把玩一下并有自己的理解。如果有错误欢迎大家指出。



    文/LonlyCat(简书作者)
    原文链接:http://www.jianshu.com/p/e7c5e2400935
    著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
    展开全文
  • iOS 11导航返回按钮偏移的问题: 参考:http://blog.csdn.net/spicyShrimp/article/details/77891717 http://blog.csdn.net/spicyShrimp/article/details/78201042 http://www.jianshu.com/p/352f101d6df1   ...

    iOS 11导航返回按钮偏移的问题:

    参考:http://blog.csdn.net/spicyShrimp/article/details/77891717

    http://blog.csdn.net/spicyShrimp/article/details/78201042

    http://www.jianshu.com/p/352f101d6df1

     

     

    1、MJ刷新异常,上拉加载出现跳动刷新问题:

     

    解决办法:初始化的时候增加以下代码(tableView和collectionView类似)

     

        if (@available(iOS11.0, *)) {

            _tableView.contentInsetAdjustmentBehavior =UIScrollViewContentInsetAdjustmentNever;

            _tableView.contentInset =UIEdgeInsetsMake(64,0,49,0);//64和49自己看效果,是否应该改成0

            _tableView.scrollIndicatorInsets =_tableView.contentInset;

        }

     

    2、tableView的section之间间距变大问题:

    解决办法:初始化的时候增加以下代码

     

         self.tableView.estimatedRowHeight =0;

         self.tableView.estimatedSectionHeaderHeight =0;

         self.tableView.estimatedSectionFooterHeight =0;

     

    3、导航栏按钮偏移20像素问题

     

    解决办法:

    楼主写的分类:UIViewController+BarButton

    代码如下:

    //左侧一个图片按钮的情况

     

    - (void)addLeftBarButtonWithImage:(UIImage *)image action:(SEL)action

    {

        UIView *view = [[UIViewalloc]initWithFrame:CGRectMake(0,0,44,44)];

        view.backgroundColor = [UIColorclearColor];

        

        UIButton *firstButton = [UIButtonbuttonWithType:UIButtonTypeCustom];

        firstButton.frame = CGRectMake(004444);

        [firstButton setImage:imageforState:UIControlStateNormal];

        [firstButton addTarget:selfaction:actionforControlEvents:UIControlEventTouchUpInside];

        

        if (!SYSTEM_VERSION_LESS_THAN(@"11")) {

            firstButton.contentHorizontalAlignment =UIControlContentHorizontalAlignmentLeft;

            [firstButton setImageEdgeInsets:UIEdgeInsetsMake(0, -5 *kScreenWidth /375.0,0,0)];

        }

        

        UIBarButtonItem *leftBarButtonItem = [[UIBarButtonItemalloc]initWithCustomView:firstButton];

     

        self.navigationItem.leftBarButtonItem = leftBarButtonItem;

    }

    //右侧一个图片按钮的情况

    - (void)addRightBarButtonWithFirstImage:(UIImage *)firstImage action:(SEL)action

    {

        UIView *view = [[UIViewalloc]initWithFrame:CGRectMake(0,0,44,44)];

        view.backgroundColor = [UIColorclearColor];

        

        UIButton *firstButton = [UIButtonbuttonWithType:UIButtonTypeCustom];

        firstButton.frame = CGRectMake(004444);

        [firstButton setImage:firstImageforState:UIControlStateNormal];

        [firstButton addTarget:selfaction:actionforControlEvents:UIControlEventTouchUpInside];

        

        if (!SYSTEM_VERSION_LESS_THAN(@"11")) {

            firstButton.contentHorizontalAlignment =UIControlContentHorizontalAlignmentRight;

            [firstButton setImageEdgeInsets:UIEdgeInsetsMake(0,0,0, -5 *kScreenWidth /375.0)];

        }

        

        UIBarButtonItem *rightBarButtonItem = [[UIBarButtonItemalloc]initWithCustomView:firstButton];

     

        self.navigationItem.rightBarButtonItem = rightBarButtonItem;

    }

    //右侧为文字item的情况

    - (void)addRightBarButtonItemWithTitle:(NSString *)itemTitle action:(SEL)action

    {

     

        UIButton *rightbBarButton = [[UIButtonalloc]initWithFrame:CGRectMake(0,0,88,44)];

        [rightbBarButton setTitle:itemTitle forState:(UIControlStateNormal)];

        [rightbBarButton setTitleColor:kDarkOneColorforState:(UIControlStateNormal)];

        rightbBarButton.titleLabel.font = [UIFontsystemFontOfSize:14];

        [rightbBarButton addTarget:selfaction:actionforControlEvents:(UIControlEventTouchUpInside)];

        if (!SYSTEM_VERSION_LESS_THAN(@"11")) {

            rightbBarButton.contentHorizontalAlignment =UIControlContentHorizontalAlignmentRight;

            [rightbBarButton setTitleEdgeInsets:UIEdgeInsetsMake(0,0,0, -5 * kScreenWidth/375.0)];

        }

        

        self.navigationItem.rightBarButtonItem = [[UIBarButtonItemalloc]initWithCustomView:rightbBarButton];

    }

    //左侧为文字item的情况

    - (void)addLeftBarButtonItemWithTitle:(NSString *)itemTitle action:(SEL)action

    {

        UIButton *leftbBarButton = [[UIButtonalloc]initWithFrame:CGRectMake(0,0,44,44)];

        [leftbBarButton setTitle:itemTitleforState:(UIControlStateNormal)];

        [leftbBarButton setTitleColor:kDarkOneColorforState:(UIControlStateNormal)];

        leftbBarButton.titleLabel.font = [UIFontsystemFontOfSize:16];

        [leftbBarButton addTarget:selfaction:actionforControlEvents:(UIControlEventTouchUpInside)];

        if (!SYSTEM_VERSION_LESS_THAN(@"11")) {

            leftbBarButton.contentHorizontalAlignment =UIControlContentHorizontalAlignmentLeft;

            [leftbBarButton setTitleEdgeInsets:UIEdgeInsetsMake(0, -5  *kScreenWidth/375.0,0,0)];

        }

        

        self.navigationItem.leftBarButtonItem = [[UIBarButtonItemalloc]initWithCustomView:leftbBarButton];

    }

     

    //右侧两个图片item的情况

    - (void)addRightTwoBarButtonsWithFirstImage:(UIImage *)firstImage firstAction:(SEL)firstAction secondImage:(UIImage*)secondImage secondAction:(SEL)secondAction

    {

        UIView *view = [[UIViewalloc]initWithFrame:CGRectMake(0,0,80,44)];

        view.backgroundColor = [UIColorclearColor];

        

        UIButton *firstButton = [UIButtonbuttonWithType:UIButtonTypeCustom];

        firstButton.frame = CGRectMake(4463030);

        [firstButton setImage:firstImageforState:UIControlStateNormal];

        [firstButton addTarget:selfaction:firstActionforControlEvents:UIControlEventTouchUpInside];

        if (!SYSTEM_VERSION_LESS_THAN(@"11")) {

            firstButton.contentHorizontalAlignment =UIControlContentHorizontalAlignmentRight;

            [firstButton setImageEdgeInsets:UIEdgeInsetsMake(0,0,0, -5 * kScreenWidth/375.0)];

        }

        [view addSubview:firstButton];

        

        UIButton *secondButton = [UIButtonbuttonWithType:UIButtonTypeCustom];

        secondButton.frame = CGRectMake(663030);

        [secondButton setImage:secondImageforState:UIControlStateNormal];

        [secondButton addTarget:selfaction:secondActionforControlEvents:UIControlEventTouchUpInside];

        if (!SYSTEM_VERSION_LESS_THAN(@"11")) {

            secondButton.contentHorizontalAlignment =UIControlContentHorizontalAlignmentRight;

            [secondButton setImageEdgeInsets:UIEdgeInsetsMake(0,0,0, -5 * kScreenWidth/375.0)];

        }

        [view addSubview:secondButton];

        

        UIBarButtonItem *rightBarButtonItem = [[UIBarButtonItemalloc]initWithCustomView:view];

     

        self.navigationItem.rightBarButtonItem = rightBarButtonItem;

    }

     

    在你的控制器里边,直接[self addleft...]就可以调用,如果觉得坐标有问题,可以自行处理变更

    如果你的需求是三个四个item按钮,可以仿照上边两个item按钮的方法,自行处理。

     

    ===========

    http://blog.csdn.net/sodaslay/article/details/78074625

     

    2.scrollview的内容适配contentInsetAdjustmentBehavior(http://blog.csdn.net/HDFQQ188816190/article/details/78050242?locationNum=3&fps=1)

     

      self.tab.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;//UIScrollView也适用

     

    1. 1.UIScrollView的属性contentInsetAdjustmentBehavior  
    2. 2.UIScrollView的只读属性adjustedContentInset  
    3. 3.UIView的只读属性safeAreaInsets 

     

     

     

    ==========下面是一个简单的导航按钮解决

     

    #import <UIKit/UIKit.h>

     

    @interface UIBarButtonItem (LeftBarbutton)

    /*

     *添加返回按钮

     *imageStr  按钮图片名称

     *titleStr  按钮标题名称

     *action    方法,要在调用的那个控制器中实现

     *target    哪个控制器调用的

     */

    +(NSArray *)backBtn:(SEL)action target:(id)target image:(NSString *)imageStr title:(NSString *)titleStr;

     

    /*

     *添加右侧按钮

     *imageStr  按钮图片名称

     *titleStr  按钮标题名称

     *action    方法,要在调用的那个控制器中实现

     *target    哪个控制器调用的

     */

    +(NSArray *)addrightBtn:(SEL)action target:(id)target image:(NSString *)imageStr title:(NSString *)titleStr;

     

    @end

     

     

    ********************************

     

    #import "UIBarButtonItem+LeftBarbutton.h"

     

    @implementation UIBarButtonItem (LeftBarbutton)

     

    //添加导航返回按钮

    +(NSArray *)backBtn:(SEL)action target:(id)target image:(NSString *)imageStr title:(NSString *)titleStr{

        UIButton *backBtn=[[UIButtonalloc]initWithFrame:CGRectMake(0,0,80,44)];

        [backBtn setTitleColor:[UIColorblackColor]forState:UIControlStateNormal];

        backBtn.titleLabel.font=[UIFontsystemFontOfSize:12];

        UIBarButtonItem *backbtn=[[UIBarButtonItemalloc]initWithCustomView:backBtn];

        UIBarButtonItem *fixBtn=[[UIBarButtonItemalloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpacetarget:selfaction:nil];

        

        if(titleStr && ![titleStr isEqualToString:@""]){

            [backBtn setTitle:titleStrforState:UIControlStateNormal];

        }

        

        if(imageStr && ![imageStr isEqualToString:@""]){

            fixBtn.width=-30;

            [backBtn setImage:[UIImageimageNamed:imageStr]forState:UIControlStateNormal];

        }

        if(target && action){

            [backBtn addTarget:targetaction:actionforControlEvents:UIControlEventTouchUpInside];

        }

        //兼容IOS11

        CGFloat sysv= [[[UIDevicecurrentDevice]systemVersion]floatValue];

        if(sysv>=11.0){

            backBtn.contentHorizontalAlignment =UIControlContentHorizontalAlignmentLeft;

            [backBtn setImageEdgeInsets:UIEdgeInsetsMake(0,0,0,0)];

            

        }

       

        NSArray *btnArr=@[fixBtn,backbtn];

        return btnArr;

    }

     

     

    //添加导航右侧按钮

    +(NSArray *)addrightBtn:(SEL)action target:(id)target image:(NSString *)imageStr title:(NSString *)titleStr{

        UIButton *rightBtn=[[UIButtonalloc]initWithFrame:CGRectMake(0,0,80,44)];

        [rightBtn setTitleColor:[UIColorwhiteColor]forState:UIControlStateNormal];

        [rightBtn.titleLabelsetFont:[UIFontsystemFontOfSize:14weight:UIFontWeightThin]];

        UIBarButtonItem *rbtn=[[UIBarButtonItemalloc]initWithCustomView:rightBtn];

        UIBarButtonItem *fixBtn=[[UIBarButtonItemalloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpacetarget:nilaction:nil];

        

        

        if(titleStr && ![titleStr isEqualToString:@""]){

            [rightBtn setTitle:titleStrforState:UIControlStateNormal];

            fixBtn.width=0;

        }

        

        if(imageStr && ![imageStr isEqualToString:@""]){

            [rightBtn setImage:[UIImageimageNamed:imageStr]forState:UIControlStateNormal];

            fixBtn.width=-20;

        }

        if(target && action){

            [rightBtn addTarget:targetaction:actionforControlEvents:UIControlEventTouchUpInside];

        }

        //兼容IOS11

        CGFloat sysv= [[[UIDevicecurrentDevice]systemVersion]floatValue];

        if(sysv>=11.0){

            rightBtn.contentHorizontalAlignment =UIControlContentHorizontalAlignmentRight;

            [rightBtn setTitleEdgeInsets:UIEdgeInsetsMake(0,0,0,0)];

        }

        NSArray *rightBtnArr=@[fixBtn,rbtn];

        return rightBtnArr;

    }

    @end

    使用:

     

    //设置导航右边按钮

    -(void)addrightBtn{

        

        self.navigationItem.rightBarButtonItems=[UIBarButtonItemaddrightBtn:@selector(addListBtn)target:selfimage:@""title:@"我的投资"];

    }

     

     

    -(void)addListBtn{

       

    }

    //返回按钮

    -(void)addbackBtn{

        

        self.navigationItem.leftBarButtonItems=[UIBarButtonItembackBtn:@selector(backBtn)target:selfimage:@"icon_navigation_back"title:@""];

    }

    -(void)backBtn{

        

    }

     

    ==============IOS10  之后push出去后导航标题不显示的问题:

    https://www.cnblogs.com/PaulpauL/p/6017817.html

    原因是“iOS10在加载导航栏是总会加载系统的”。如果他说得对的话,也就是说push时系统会将自带的导航栏置顶,而隐藏后再显示只会显示自定义的导航栏。

    =========

    iOS10 title和leftBarButtonItem不显示

    http://www.jianshu.com/p/402816df3903

     

     

    =======ios11 tableview 显示偏移的问题:

    http://blog.csdn.net/ycm1101743158/article/details/78086152

    ================导航基类==============

    #import "LYBNavigationController.h"
    
    @interface LYBNavigationController ()
    {
        
        UIImage * shadowView;
        
    }
    @end
    
    @implementation LYBNavigationController
    /**
     这个方法在类中的第一个方法被调用时会调用一次
     */
    + (void)initialize
    {
        UINavigationBar *bar = [UINavigationBar appearance];
        [bar setBarTintColor:[UIColor whiteColor]];
        [bar setTitleTextAttributes:@{NSFontAttributeName : [UIFont systemFontOfSize:20],NSForegroundColorAttributeName:[UIColor blackColor]}];
    //    [bar setShadowImage:[[UIImage alloc] init]];//隐藏导航下面的那根线
        // 设置item
        UIBarButtonItem *item = [UIBarButtonItem appearance];
        // UIControlStateNormal
        NSMutableDictionary *itemAttrs = [NSMutableDictionary dictionary];
        itemAttrs[NSForegroundColorAttributeName] = [UIColor blackColor];
        itemAttrs[NSFontAttributeName] = [UIFont systemFontOfSize:17];
        [item setTitleTextAttributes:itemAttrs forState:UIControlStateNormal];
        // UIControlStateDisabled
        NSMutableDictionary *itemDisabledAttrs = [NSMutableDictionary dictionary];
        itemDisabledAttrs[NSForegroundColorAttributeName] = [UIColor lightGrayColor];
        [item setTitleTextAttributes:itemDisabledAttrs forState:UIControlStateDisabled];
    }
    - (void)viewDidLoad {
        [super viewDidLoad];
        // 如果滑动移除控制器的功能失效,清空代理(让导航控制器重新设置这个功能)
        [self.interactivePopGestureRecognizer setEnabled:NO];
        
    }
    - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
    {
        
        if (self.childViewControllers.count > 0) { // 如果push进来的不是第一个控制器
            
            UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
            [button setImage:[UIImage imageNamed:@"navi_arrow_back"] forState:UIControlStateNormal];
            button.frame = CGRectMake(0, 0, 40, 30);
            // 让按钮内部的所有内容左对齐
            button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
            //        [button sizeToFit];
            // 让按钮的内容往左边偏移10
            button.contentEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0);
            [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
            [button setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted];
            [button addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchUpInside];
            
            // 修改导航栏左边的item
            viewController.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:button];
            
            // 隐藏tabbar
            viewController.hidesBottomBarWhenPushed = YES;
        }else{
            if(self.isAlwaysShadow)
            {
                
            }else{
                
            }
        
        }
        
        // 这句super的push要放在后面, 让viewController可以覆盖上面设置的leftBarButtonItem
        [super pushViewController:viewController animated:animated];
        
    }
    - (UIViewController *)popViewControllerAnimated:(BOOL)animated{
        
        if (self.childViewControllers.count > 2){
            
            
        }else{
            
            if(self.isAlwaysShadow)
            {
                
            }else{
                
            }
            
        }return [super popViewControllerAnimated:animated];
        
    }
    - (void)back
    {
        [self popViewControllerAnimated:YES];
    }
    
    
    @end

     

    展开全文
  • iOS导航栏侧滑失效问题 关于iOS的导航栏, 想必各个iOS开发者都是经常要面对的问题.也是必须熟练掌握的一个技术点. 比较坑的有两方面.1.一方面是导航栏上的控件位置问题. 2.一方面是导航栏的返回按钮自定义问题.今天...

    iOS导航栏侧滑失效问题

    关于iOS的导航栏, 想必各个iOS开发者都是经常要面对的问题.也是必须熟练掌握的一个技术点.

    比较坑的有两方面.
    • 1.一方面是导航栏上的控件位置问题.
    • 2.一方面是导航栏的返回按钮自定义问题.

    今天我主要分享一下自己对这个问题的解决方案的看法.首先我们先来看看iOS中如何设置返回按钮.

    iOS中设置返回按钮有两种方式.
    • 一种是在上一级控制器配置.(配置backBarButtonItem)
    • 一种是在本控制器配置.(leftBarButtonItem)

    前者只能配置文字或者图片.而不能用自定义的View去配置.苹果的官方文档有如下解释

    When this navigation item is immediately below the top item in the stack, 
    the navigation controller derives the back button for the navigation bar 
    from this navigation item. When this property is nil, the navigation item 
    uses the value in its title property to create an appropriate back button. If 
    you want to specify a custom image or title for the back button, you can 
    assign a custom bar button item (with your custom title or image) to this 
    property instead. When configuring your bar button item, do not assign a 
    custom view to it; the navigation item ignores custom views in the back 
    bar button anyway.
    
    当这个属性是nil的是否, 导航栏使用它的title属性创建一个返回按钮.如果你要为
    返回按钮自定义一张图片或者文字, 你可以赋值文字或者图片给UIBarButtonItem
    对象.但是对于自定义的View, 在backBarButtonItem中会被忽略.

    后者可以很方便的自定义返回按钮.

    当同时也存在一个致命的缺点, 就是用leftBarButtonItem自定义返回按钮后, 侧滑手势会失效.如下代码:

    UIView *redView = [UIView new];
    redView.width = redView.height = 100;
    UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithCustomView: redView];
    self.navigationItem.leftBarButtonItem = item;

    具体原因:

    这是为什么呢?从iOS7开始, 系统为UINavigationController, 提供了interactivePopGestureRecognizer手势, 用于右滑返回(pop).但是如果使用leftBarButtonItem属性自定义了返回按钮, 就会造成手势失效.要知道具体原因, 我们还要了解, interactivePopGetureRecognizer从手势触发到行为发生, 要经历以下过程.

    1240
    Paste_Image.png


    interactivePopGestureRecogizer还存在, 但没有起作用.是因为delegate里被阻断了没有调用target/action.或者是调用了, 但没有运行动画.
    如果我们知道action的名字, 则可以添加一个自定义的滑动手势, 字节调用系统的action.但是API文档没有提供, 所以该action应该是一个私有的API.使用私有API会造成AppStore审核被拒绝, 所以这个思路也不可取.

    那么, 我们就要自己实现滑动返回的动画action, 要么自己重写interfactivePopGestureRecognizer手势的delegate以让手势继续下去, 触发系统的action里面对应的动画.

    实现方法:

    自定义NavigationController, 遵守手势协议.
    设置interactivePopGestureRecognizer手势的代理对象为自身(自定义的navigationController自身)

    - (void)viewDidLoad { 
    [super viewDidLoad];
    self.interactivePopGestureRecognizer.delegate = self; 
    }

    让手势生效

    - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { 
      if (self.viewControllers.count <= 1 ) { 
          return NO; 
      } 
      return YES; 
    }
    
    // 允许同时响应多个手势
    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer        
    shouldRecognizeSimultaneouslyWithGestureRecognizer:
    (UIGestureRecognizer *)otherGestureRecognizer { 
       return YES;
    }

    禁止响应手势的是否ViewController中scrollView跟着滚动

    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer 
    shouldBeRequiredToFailByGestureRecognizer:
    (UIGestureRecognizer *)otherGestureRecognizer {    
    return [gestureRecognizer isKindOfClass:
    UIScreenEdgePanGestureRecognizer.class];
    }

    在push动画发生的时候, 禁止滑动手势, 因为push动作还没完成, 逻辑上是不允许这个是否进行滑动.重写pushViewController:XX方法.

    self.interactivePopGestureRecognizer.enabled = NO;

    在使用navigationController的viewController里面添加

    - (void)viewDidAppear:(BOOL)animated { 
        [super viewDidAppear:animated];     
        self.navigationController.interactivePopGestureRecognizer.enabled = YES;
     }

    或者使导航控制器成为自身的代理, 监听Push完成后的ViewController

    - (void)navigationController:(UINavigationController *)navigationController       
    didShowViewController:(UIViewController *)viewController                    
    animated:(BOOL)animate {    
    //控制器入栈之后,启用手势识别    
      if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)])        
          self.interactivePopGestureRecognizer.enabled = YES;
    }
    
    // 如果要这样做, 同时应该让该导航控制器成为自己的代理
    // 在上面的viewDidLoad里添加如下一句代码
    self.delegate = self

    后续

    如果你不想自己实现.这里有一个韩国开发者利用runtime技术写的框架, 解决了该问题.https://github.com/devxoul/SwipeBack.
    .但是实际测试中, 发现该框架还有不足之处, 如有遇到使用该框架还是无效的, 可以参照上面的步骤进行更改, 自定义导航控制器.关于导航栏上的控件位置问题, 会在下一篇进行介绍.

    转自:http://www.jianshu.com/p/f9f1d1db8e1e

    展开全文
  • iOS导航栏文字按钮字体的大小修改

    昨天遇到个需求是通过导航栏的按钮去跳转到一个网页列表展示东西,需要按钮名称直接,简单。就用了文字按钮,

    使用系统的按钮的话字体有些偏大不合适

    就要修改字体大小,本人使用的第二种方法

    两个方法:

    1,在导航栏放置按钮,如果是右边记得让文字居右显示;

    //    UIButton *right = [UIButton buttonWithType:UIButtonTypeCustom];
    //    right.frame = CGRectMake(0, 0, 100, 50);
    //    [right addTarget:self action:@selector(rightDeal) forControlEvents:UIControlEventTouchUpInside];
    //    [right setTitle:@"查看XX" forState:UIControlStateNormal];
    //    right.titleLabel.font = Font_CN(15);
    //    right.backgroundColor = [UIColor redColor];
    //    right.titleLabel.textAlignment = NSTextAlignmentRight;
    //    [right setTitleColor:DB_Blue forState:UIControlStateNormal];
    //    UIBarButtonItem *rightBut = [[UIBarButtonItem alloc]initWithCustomView:right];
    //    self.navigationItem.rightBarButtonItem = rightBut;

    代码中没有按钮文字居右的代码,这个自己找找就好

    2,也是相对比较简单的一种方法

      UIBarButtonItem *rightBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:@"查看限额" style:UIBarButtonItemStylePlain target:self action:@selector(rightDeal)];
        self.navigationItem.rightBarButtonItem = rightBarButtonItem;
    //    [self.navigationItem.rightBarButtonItem setTintColor:MainColor];
        
        [self.navigationItem.rightBarButtonItem setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:Font_CN(14), NSFontAttributeName, nil] forState:UIControlStateNormal];

    Font_CN(14)  为字体大小可以自己设置的


    展开全文
  • iOS开发的工作当中,Push和Pop经常用于界面之间的跳转和返回。... 这个想法非常棒,但是系统给我们规定手势触发的范围必须是屏幕左侧边缘,还有如果我们自定制了返回按钮或者隐藏了导航栏,也就是执
  • 第二个界面的导航栏隐藏掉过后,iOS7之后的左划pop到上个界面的手势不能正常使用。下面就简单介绍下我的解决这个问题的思路。 注: V1是控制器1 V2是V1 push后的控制器2 V3是V1 push后的控制器3 1.隐藏导航栏 方法...
  • 之前有写过iOS11导航按钮位置的一篇解决方案,当时的解决思路是针对navigationItem做调整,强制修改约束 具体细节可以跳转iOS11 导航按钮位置问题的解决 ...1.界面在push和pop之
  • 当自定义返回按钮后右滑返回会失效 //返回按钮 self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"return"] style:(UIBarButtonItemStylePlain) target:...
  • 还有就是如果我们给导航的左按钮(leftBar)自定义了,那右滑返回也会失效。 想想他还真是挺烦人,索性直接隐藏了算了,自己做起来更好。 这个时候我们用以下方法来隐藏导航栏,根据自己的需求,写在生命周期的不同...
  • //导航控制器全局设置导航按钮 //基础的导航控制器,统一处理返回按钮偏移的问题 #import <UIKit/UIKit.h> NS_ASSUME_NONNULL_BEGIN @interface QMWNBasenav : UINavigationController @property ...
  • 当我们使用了系统的导航栏时,默认点击返回按钮是 pop 回上一个界面。但是在有时候,我们需要在点击导航栏的返回按钮时不一定要 pop 回上一界面,比如一个视频播放界面,进入横屏后,默认点击返回按钮仍然是 pop ...
  • iOS-自定义导航栏后侧滑返回功能失效 时间 2016-03-16 21:30:21 程序员头条 原文 http://www.iswifting.com/2016/03/16/ios-self-navigation/ 主题 C语言 iOS开发 文章目录 iPhone有一个回退按钮在所有的...
  • 方法一:在dealloc里面书写监听事件,因为只有pop才会调用dealloc,push不会掉用 - (void)dealloc {YLLog(@"123"); } 方法二:在- (void)viewWillDisappear:(BOOL)animated中调用 - (void)...
  • 使用系统的返回按钮当然什么问题都没有,但是如果要自定义返回按钮 ,将会出现系统右滑手机失效的问题。网上解决方法很多。这里只简单提供一种较为简单的方法. A控制器push到B控制器。 在B控制器里,首先加入如下...
  • 我相信针对每一个iOS开发者来说~除了根视图控制器外~所有的界面通过导航栏push过去的界面都是可以通过右滑来返回上一个界面~其实~在很多应用和APP中~用户已经习惯了这个功能~然而~作为开发者的我们~也并没有为此做些...
1 2 3 4 5 ... 20
收藏数 2,133
精华内容 853
关键字:

11 ios 导航按钮失效