【转】自定义iOS的Back按钮(backBarButtonItem)和pop交互手势(interactivepopgesturerecognizer) --- 不错

时间:2022-06-02 07:50:39

原文网址:http://blog.csdn.net/joonsheng/article/details/41362499

说到自定义UINavigetionController的返回按钮,iOS7以后,多了一个“<” 这样的返回图标,而目前主流的应用,都是只保留了“<”,而去掉了文字,那么怎么样自定义一个自己的“<"按钮,或者用系统的“<”,但不要文字呢?

1.设置中的返回按钮(带文字)

【转】自定义iOS的Back按钮(backBarButtonItem)和pop交互手势(interactivepopgesturerecognizer) --- 不错

2.音乐中播放时(不带文字)

【转】自定义iOS的Back按钮(backBarButtonItem)和pop交互手势(interactivepopgesturerecognizer) --- 不错

1、直接上答案

  1. //下面这两句是让系统的返回按钮的文字为空,从而达到隐藏文字的作用
  2. UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStyleBordered target:nil action:nil];
  3. self.navigationItem.backBarButtonItem = backItem;
  4. //这句就是push了,所以在push前加上这样一句,就保留了系统的自带的“<",并且文字为空
  5. [self.navigationController pushViewController:registerVC animated:YES];

注:本文代码,如果没有说明,都是从A导航视图push到B导航视图时,在A导航视图里设置的代码。

看图:

【转】自定义iOS的Back按钮(backBarButtonItem)和pop交互手势(interactivepopgesturerecognizer) --- 不错

2、带着问题看答案:

1、上面的方法,只是利用了系统的自带"<", 有人可能就问,那如果我想自定义图标呢?

  1. //下面两行就是自定义,替换系统的“<"图标
  2. 【1】    [self.navigationController.navigationBar setBackIndicatorImage:[UIImage imageNamed:@"navibar_back_btn_bg_normal.png"]];
  3. [self.navigationController.navigationBar setBackIndicatorTransitionMaskImage:[UIImage imageNamed:@"navibar_back_btn_bg_normal.png"]];
  4. UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStyleBordered target:nil action:nil];
  5. self.navigationItem.backBarButtonItem = backItem;

这个方法,如果只是适配iOS 7以上,那么,是目前比较好的解决方案了。

特点:

1.实现了自定义图标,可以没有文字,

2.保存了iOS 7以上系统的pop手势返回。

如果要适配iOS 6,那么就要判断系统版本,如果大于iOS 7,就用上面的代码,如果低于iOS 7.0,就用另外的代码(下面在介绍)

效果如下图:

【转】自定义iOS的Back按钮(backBarButtonItem)和pop交互手势(interactivepopgesturerecognizer) --- 不错

backItem;

2、那么,我们在A视图设置的代码,系统是如何实现从A视图push到B视图后,显示在B视图的?

看图:

【转】自定义iOS的Back按钮(backBarButtonItem)和pop交互手势(interactivepopgesturerecognizer) --- 不错

显示原理【2】:

1、如果B视图有一个自定义的左侧按钮(leftBarButtonItem),则会显示这个自定义按钮;

2、如果B没有自定义按钮,但是A视图的backBarButtonItem属性有自定义项,则显示这个自定义项;

3、如果前2条都没有,则默认显示一个后退按钮,后退按钮的标题是A视图的标题。

3、如果理解了第2点,那么怎样自定义代码,才能适配iOS 6和iOS 7以上呢?

自定义要求:

1.自定义图标,文字可要可不要。

2.对于iOS 7以上,保留pop手势.

分析:如果在A视图自定义了返回按钮,又要适配iOS6 ,但由于iOS6 下没有手势返回,所以只能点击左上角返回,怎么处理?

直接上答案:

方案一【3】:

在A视图中:

  1. if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0"))  //如果系统版本在iOS 7.0以上,执行
  2. {
  3. [self.navigationController.navigationBar setBackIndicatorImage:[UIImage imageNamed:@"name="navibar_back_btn_bg_normal.png"]];
  4. [self.navigationController.navigationBar setBackIndicatorTransitionMaskImage:[UIImage imageNamed:@"navibar_back_btn_bg_normal.png"]];
  5. UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStyleBordered target:nil action:nil];
  6. self.navigationItem.backBarButtonItem = backItem;
  7. }


在B视图中:

  1. if (SYSTEM_VERSION_LESS_THAN(@"7.0"))  //如果系统版本在iOS 7.0以下(不包括7.0),执行
  2. {
  3. //导航条返回按钮
  4. UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
  5. [button setImage:[UIImage imageNamed:@"navibar_back_btn_bg_normal.png]forState:UIControlStateNormal];
  6. [button setFrame:CGRectMake(0,0,30,30)">];
  7. [button addTarget:self action:@selector(jumpBack:) forControlEvents:UIControlEventTouchUpInside];
  8. UIBarButtonItem * barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:button];
  9. self.navigationItem.leftBarButtonItem = barButtonItem;
  10. }


  1. #pragma mark - 跳转回去
  2. - (void)jumpBack:(id)sender{
  3. [self.navigationController popViewControllerAnimated:YES];
  4. }

方案二:

//在A视图中:

  1. //开启iOS7的滑动返回效果
  2. if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
  3. self.navigationController.interactivePopGestureRecognizer.delegate = nil;
  4. }
  5. [self.navigationController pushViewController:registerVC animated:YES];

//在B视图中(ViewDidLoad):

  1. //导航条返回按钮
  2. UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
  3. [button setImage:[UIImage imageNamed:@"navibar_back_btn_bg_normal.png]forState:UIControlStateNormal];
  4. [button setFrame:CGRectMake(0,0,30,30)];
  5. [button addTarget:self action:@selector(jumpBack:) forControlEvents:UIControlEventTouchUpInside];
  6. UIBarButtonItem * barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:button];
  7. self.navigationItem.leftBarButtonItem = barButtonItem;


  1. #pragma mark - 跳转回去
  2. - (void)jumpBack:(id)sender{
  3. [self.navigationController popViewControllerAnimated:YES];
  4. }


这个方案,不用适配iOS 6和iOS 7,与方案一区别是,箭头比较靠右边,为什么?说到这个,我下一篇文章在会针对Navigation层次结构在说吧。

如图:
【转】自定义iOS的Back按钮(backBarButtonItem)和pop交互手势(interactivepopgesturerecognizer) --- 不错

方案三:

在B视图中:
  1. - (void)viewWillAppear:(BOOL)animated
  2. {
  3. // 注意,这个<span style="font-family: Arial, Helvetica, sans-serif;">interactivePopGestureRecognizer</span><span style="font-family: Arial, Helvetica, sans-serif;">属性是iOS 7才有的</span>
  4. self.navigationController.interactivePopGestureRecognizer.delegate = self;
  5. }
  1. //导航条返回按钮
  2. UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
  3. [button setImage:[UIImage imageNamed:@"navibar_back_btn_bg_normal.png"]
  4. forState:UIControlStateNormal];
  5. [button setFrame:CGRectMake(0,0,30,30)];
  6. [button addTarget:self action:@selector(jumpBack:) forControlEvents:UIControlEventTouchUpInside];
  7. UIBarButtonItem * barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:button];
  8. self.navigationItem.leftBarButtonItem = barButtonItem;
  9. #pragma mark - 跳转回去
  10. - (void)jumpBack:(id)sender{
  11. [self.navigationController popViewControllerAnimated:YES];
  12. }

3、自定义几点说明

1.返回文字可以自定义为照片

  1. UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed: @"navibar_back_btn_bg_normal.png"] style:(UIBarButtonItemStylePlain) target:nil action:nil];
  2. self.navigationItem.backBarButtonItem = backItem;

看图:

【转】自定义iOS的Back按钮(backBarButtonItem)和pop交互手势(interactivepopgesturerecognizer) --- 不错


第二个"<",就是自定的图片,这个自定义有意思吗?大家看着用吧

2.自定义视图无效!

  1. UIView * view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 30, 44)];
  2. view.backgroundColor = [UIColor colorWithRed:0.263 green:1.000 blue:0.311 alpha:1.000];
  3. UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithCustomView:view];
  4. self.navigationItem.backBarButtonItem = backItem;

3.自定义按钮~

注意这个相对第1个自定义照片的区别:backBarButtonItem不能用View视图方法自定义,而leftBarButtonItem可以哦!

  1. UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
  2. [button setImage:[UIImage imageNamed:@"navibar_back_btn_bg_normal.png"] forState:UIControlStateNormal];
  3. [button setFrame:CGRectMake(0, 0, 30, 44)];
  4. [button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
  5. UIBarButtonItem * barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:button];
  6. self.navigationItem.<span style="color:#ff0000;">leftBarButtonItem</span> = barButtonItem;

这个自定义,根据【2】,可以知道其作用,在这里不在多说。

4.pop手势

  1. //官方文档:
  2. NS_CLASS_AVAILABLE_IOS(2_0) @interface UINavigationController : UIViewController
  3. @property(nonatomic, assign) id<UINavigationControllerDelegate> delegate;
  4. @property(nonatomic, readonly) UIGestureRecognizer *interactivePopGestureRecognizer NS_AVAILABLE_IOS(7_0);

以上的方法,都是基于系统自带的UINavigationController来自定义,如果不是系统的,比如淘宝的是自定义的UINavigation,所以没有利用系统的pop手势,而是自定义手势。又比如天猫的只用到【2】的改变图标,但文字都是统一的“返回”,并且部分页面,不用pop手势,直接弹回去。【分析于:2014.11.23日】

最后,大家都试试自定义自己的back按钮吧!如果你有更多更好的自定义方法,记得分享哦!还有很多细节我没有说到,如果大家感兴趣的,可以自己在深入研究一下哦~

4、附录:

【1】关于系统自带的“<”图标的官方解释:

  1. /*
  2. The back indicator image is shown beside the back button.
  3. The back indicator transition mask image is used as a mask for content during push and pop transitions
  4. Note: These properties must both be set if you want to customize the back indicator image.
  5. */
  6. @property(nonatomic,retain) UIImage *backIndicatorImage NS_AVAILABLE_IOS(7_0) UI_APPEARANCE_SELECTOR;
  7. @property(nonatomic,retain) UIImage *backIndicatorTransitionMaskImage NS_AVAILABLE_IOS(7_0) UI_APPEARANCE_SELECTOR;

根据上面文档:

1、只有这两个属性都设置了,才会显示自定义的图片。

2、这两个属性,只能用于iOS 7以上。

3、很多人问为什么要设置“backIndicatorTransitionMaskImage”这个属性,看官方文档就知道,当push、pop时显示的是这张image,但是疑问的是,当我设置这张照片跟“backIndicatorImage”属性的照片不一样时,系统不管是push,还是pop,还是完成时,都只会显示"backIndicatorImage"属性设置的照片。但由于文档没有更多信息,所以,这个问题我也就没有找到答案。

【2】参考一大神的总结:

UINavigationController Class Reference去,在“Updating the Navigation Bar”小节,有这么一段话:

The bar button item on the left side of the navigation bar allows for navigation back to the previous view controller on the navigation stack. The navigation controller updates the left side of the navigation bar as follows:

  • If the new top-level view controller has a custom left bar button item, that item is displayed. To specify a custom left bar button item, set the leftBarButtonItem property of the view controller’s navigation item.
  • If the top-level view controller does not have a custom left bar button item, but the navigation item of the previous view controller has a valid item in itsbackBarButtonItem property, the navigation bar displays that item.
  • If a custom bar button item is not specified by either of the view controllers, a default back button is used and its title is set to the value of the title property of the previous view controller—that is, the view controller one level down on the stack. (If there is only one view controller on the navigation stack, no back button is displayed.)

我大致解释一下,使用pushViewController切换到下一个视图时,navigation controller按照以下3条顺序更改导航栏的左侧按钮。

1、如果B视图有一个自定义的左侧按钮(leftBarButtonItem),则会显示这个自定义按钮;

2、如果B没有自定义按钮,但是A视图的backBarButtonItem属性有自定义项,则显示这个自定义项;

3、如果前2条都没有,则默认显示一个后退按钮,后退按钮的标题是A视图的标题。

   原文链接:http://zgia.net/?p=306

【3】关于判断处理说明,和判断系统版本代码

  1.说明:如果系统在7.0以上,那么由于有属性【1】,所以非常容易在A视图push前处理,但是iOS 6系统下,没有这个属性,又利用【2】原理,所以在B视图下,自定义一个leftBarButtonItem按钮,处理点击事件,这就是我目前所做到的,最好的方案。
  2.系统版本判断代码
  1. //检查系统版本
  2. #define SYSTEM_VERSION_EQUAL_TO(v)                  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
  3. #define SYSTEM_VERSION_GREATER_THAN(v)              ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
  4. #define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
  5. #define SYSTEM_VERSION_LESS_THAN(v)                 ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
  6. #define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v)     ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)

官方文档:

  1. + (UIDevice *)currentDevice;
  2. @property(nonatomic,readonly,retain) NSString    *name;              // e.g. "My iPhone"
  3. @property(nonatomic,readonly,retain) NSString    *model;             // e.g. @"iPhone", @"iPod touch"
  4. @property(nonatomic,readonly,retain) NSString    *localizedModel;    // localized version of model
  5. @property(nonatomic,readonly,retain) NSString    *systemName;        // e.g. @"iOS"
  6. @property(nonatomic,readonly,retain) NSString    *systemVersion;     // e.g. @"4.0"
  7. @property(nonatomic,readonly) UIDeviceOrientation orientation;       // return current device orientation.  this will return UIDeviceOrientationUnknown unless device orientation notifications are being generated.
  8. @property(nonatomic,readonly,retain) NSUUID      *identifierForVendor NS_AVAILABLE_IOS(6_0);      // a UUID that may be used to uniquely identify the device, same across apps from a single vendor.

nice~