iOS 7:如何设置UIBarButtonItem backButtonImage为UIControlStateHighlighted?
我正在尝试在正常和突出显示的状态下为后退button设置背景图像。
- (void)configureBackButtonInNavigationItem:(UINavigationItem *)item { UIBarButtonItem *backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"back" style:UIBarButtonItemStyleBordered target:nil action:NULL]; [backBarButtonItem setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor whiteColor]} forState:UIControlStateNormal]; [backBarButtonItem setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor orangeColor]} forState:UIControlStateHighlighted]; // white arrow image UIImage *normalImage = [[[UIImage imageNamed:@"btn_normal"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] resizableImageWithCapInsets:UIEdgeInsetsMake(0.f, 17.f, 0.f, 0.f)]; // orange arrow image UIImage *pressedImage = [[[UIImage imageNamed:@"btn_on_press"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] resizableImageWithCapInsets:UIEdgeInsetsMake(0.f, 17.f, 0.f, 0.f)]; [backBarButtonItem setBackButtonBackgroundImage:normalImage forState:UIControlStateNormal barMetrics:UIBarMetricsDefault]; [backBarButtonItem setBackButtonBackgroundImage:pressedImage forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault]; [backBarButtonItem setBackgroundImage:normalImage forState:UIControlStateNormal barMetrics:UIBarMetricsDefault]; [backBarButtonItem setBackgroundImage:pressedImage forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault]; NSLog(@"NORMAL: %@ HIGHLIGHTED: %@", [backBarButtonItem backButtonBackgroundImageForState:UIControlStateNormal barMetrics:UIBarMetricsDefault], [backBarButtonItem backButtonBackgroundImageForState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault]); item.backBarButtonItem = backBarButtonItem; NSLog(@"NORMAL: %@ HIGHLIGHTED: %@", [backBarButtonItem backButtonBackgroundImageForState:UIControlStateNormal barMetrics:UIBarMetricsDefault], [backBarButtonItem backButtonBackgroundImageForState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault]); }
输出如下:
NORMAL: <_UIResizableImage: 0x16b55e10> HIGHLIGHTED: <_UIResizableImage: 0x16b593d0> NORMAL: <_UIResizableImage: 0x16b55e10> HIGHLIGHTED: <_UIResizableImage: 0x16b593d0>
但是对于突出显示状态的观察结果只是对设置为正常状态的调光而不是使用正确的突出显示的图像。
正常:
突出显示(箭头仍然是白色,button意外变暗):
请不要发布有关使用leftBarButtonItem或UIButton作为自定义视图的答案。 这两种方法都可以在iOS 7上制止可反复使用的行为。
UPD:充满雷达#17481106关于这个问题。
UPD2:雷达#17481106在iOS 8中修复。
目前苹果在interactivePopGestureRecognizer
上存在bug(在刷animation后刷新导航控制器的视图,你会看到nested pop animation can result in corrupted navigation bar
控制台中的nested pop animation can result in corrupted navigation bar
警告nested pop animation can result in corrupted navigation bar
),顺便说一句,我们可以做一个小小的黑客工作围绕这个错误。
这是一个对我来说工作正常的解决scheme,
子类NavigationController类,并使其委派手势
@interface CBNavigationController:UINavigationController @结束 @implementation CBNavigationController - (void)viewDidLoad { __weak CBNavigationController * weakSelf = self; 如果([selfrespondsToSelector:@selector(interactivePopGestureRecognizer)]) { self.interactivePopGestureRecognizer.delegate = weakSelf; self.delegate = weakSelf; } } //劫持push方法来禁用手势 - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated { 如果([selfrespondsToSelector:@selector(interactivePopGestureRecognizer)]) self.interactivePopGestureRecognizer.enabled = NO; [super pushViewController:viewController animated:animated]; } #pragma标记UINavigationControllerDelegate - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animation:(BOOL)animation { //显示新控制器后,再次启用该手势 如果([selfrespondsToSelector:@selector(interactivePopGestureRecognizer)]) self.interactivePopGestureRecognizer.enabled = YES; } @结束
当用户在转换过程中开始向后滑动时,popup事件叠加并“损坏”导航堆栈。 我的解决方法是在push过渡期间临时禁用手势识别器,并在新视图控制器加载时再次启用它。 再次,这是一个UINavigationController子类更容易。
之后,您可以冷静地使用item.leftBarButtonItem
和UIButton
作为自定义视图。
除了l0gg3r的回答,你可以创build一个UINavigationBar的子类,在这里你可以实现l0gg3r的逻辑和定制你的后退button。
之后,您只需将类名称设置为从storyboard导航栏。
像这样的东西:
#import "MyNavigationBar.h" #import <objc/runtime.h> #import <objc/message.h> #pragma mark - UINavigationController category @interface UINavigationController (InteractiveGesture) <UINavigationControllerDelegate, UIGestureRecognizerDelegate> - (void)fixInteractivePopGesture; @end @implementation UINavigationController (InteractiveGesture) - (void)fixInteractivePopGesture { __weak UINavigationController *weakSelf = self; if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) { self.interactivePopGestureRecognizer.delegate = weakSelf; self.delegate = weakSelf; } [self swizzleOriginalSelectorWithName:@"pushViewController:animated:" toSelectorWithName:@"myPushViewController:animated:"]; } #pragma mark - Swizzle method - (void)swizzleOriginalSelectorWithName:(NSString *)origName toSelectorWithName:(NSString *)swizzleName { Method origMethod = class_getInstanceMethod([self class], NSSelectorFromString(origName)); Method newMethod = class_getInstanceMethod([self class], NSSelectorFromString(swizzleName)); method_exchangeImplementations(origMethod, newMethod); } - (void)myPushViewController:(UIViewController *)viewController animated:(BOOL)animated { if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) { self.interactivePopGestureRecognizer.enabled = NO; } [self myPushViewController:viewController animated:animated]; } #pragma mark UINavigationControllerDelegate - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animate { // Enable the gesture again once the new controller is shown if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) { self.interactivePopGestureRecognizer.enabled = YES; } } @end #pragma mark - MyNavigationBar @interface MyNavigationBar() @property (strong, nonatomic) UIButton *backButtonCustomView; @end @implementation MyNavigationBar - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self setup]; } return self; } - (void)awakeFromNib { [super awakeFromNib]; [self setup]; } - (void)setup { self.backButtonCustomView = [UIButton buttonWithType:UIButtonTypeCustom]; // here customize your button // eg set images for Normal state, or highlighted state, etc... // ... [self.backButtonCustomView addTarget:self action:@selector(handleBackButton:) forControlEvents:UIControlEventTouchUpInside]; self.backButton = [[UIBarButtonItem alloc] initWithCustomView: self.backButtonCustomView]; } - (void)layoutSubviews { [super layoutSubviews]; if ([[self navigationController] viewControllers].count > 1) { [self.topItem setLeftBarButtonItem:self.backButton animated:YES]; } // Enabling back "Swipe from edge to pop" feature. [self.navigationController fixInteractivePopGesture]; } - (void)handleBackButton:(id)sender { UINavigationController *nvc = [self navigationController]; [nvc popViewControllerAnimated:YES]; } - (UINavigationController *)navigationController { UINavigationController *resultNC = nil; UIViewController *vc = nil; for (UIView* next = [self superview]; next; next = next.superview) { UIResponder* nextResponder = [next nextResponder]; if ([nextResponder isKindOfClass:[UIViewController class]]) { vc = (UIViewController*)nextResponder; break; } } if (vc) { if ([vc isKindOfClass:[UINavigationController class]]) { resultNC = (UINavigationController *)vc; } else { resultNC = vc.navigationController; } } return resultNVC; } @end
然后:
干得好。 而已! 现在你可以复制/粘贴到你想要的任何项目类,只需从故事板设置类名:)
你不想自定义视图,因为它会打破刷卡,但你应该添加这一行。
self.navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self;
你的代码将如下所示。
UIImage *normalImage = [[[UIImage imageNamed:@"btn_normal"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] resizableImageWithCapInsets:UIEdgeInsetsMake(0.f, 17.f, 0.f, 0.f)]; UIImage *pressedImage = [[[UIImage imageNamed:@"btn_on_press"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] resizableImageWithCapInsets:UIEdgeInsetsMake(0.f, 17.f, 0.f, 0.f)]; UIButton *customBackButton = [UIButton buttonWithType:UIButtonTypeCustom]; [customBackButton setBackgroundImage:normalImage forState:UIControlStateNormal]; [customBackButton setBackgroundImage:pressedImage forState:UIControlStateHighlighted]; [customBackButton addTarget:self action:@selector(customBackMethod:) forControlEvents:UIControlEventTouchUpInside]; UIBarButtonItem *customBackBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:customBackButton]; self.navigationItem.leftBarButtonItem = customBackBarButtonItem; self.navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self; - (IBAction)customBackMethod:(id)sender { [self.navigationController popViewControllerAnimated:YES]; }