比來碰到一個關於導航欄前往按鈕的成績,由於之前項目外面都是用的體系默許的前往按鈕款式所以沒有想過要去更改,後來有須要將前往按鈕箭頭旁邊的文字去失落,同時將該前往按鈕的點擊事宜從新界說。一開端測驗考試自界說按鈕然後設置為leftBarButtonItem,然則如許圖片能夠跟體系自帶的紛歧樣,還有就是前往按鈕的地位跟體系自帶的紛歧樣。後來找了一些材料,發明將文字去失落比擬簡略,普通做法是掌握器中添加以下代碼,然後他的下一級掌握就有一個只要箭頭沒有文字前往按鈕:
UIBarButtonItem *backBtn = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];
self.navigationItem.backBarButtonItem = backBtn;
也能夠創立一個根掌握器在個中應用上述代碼然後讓其他掌握器繼續這個根掌握器完成批量操作。然則假如碰到須要自界說該前往的點擊事宜的時刻,在下面辦法中添加target與action是弗成行的,同時這類做法也會發生一個成績,就是現實的前往按鈕點擊區域老是比按鈕看到的規模年夜,普通是間隔箭頭左邊30間隔都可點擊。接上去我就帶年夜家一路懂得這些成績發生的緣由和若何更好的處理這些成績。
起首我們看一下依照下面代碼去失落前往按鈕文字以後的導航欄視圖的構造條理,由於導航欄的視圖加載和初始化跟viewController的view紛歧樣,不克不及再veiwDidLoad中去不雅察(viewWillAppear中也不可)要在viewDidLoad中才可以看到完全的導航欄視圖構造條理。我們可以在一個有去失落文字的前往按鈕掌握器的viewDidLoad中打上斷點然後在掌握台履行:
po [[UIWindow keyWindow] recursiveDescription]
會獲得以下輸入:
<UIWindow: 0x8d6f970; frame = (0 0; 320 480); autoresize = W+H; gestureRecognizers = <NSArray: 0x8d5dbf0>; layer = <UIWindowLayer: 0x8d717d0>> | <UILayoutContainerView: 0x8d7bbf0; frame = (0 0; 320 480); autoresize = W+H; gestureRecognizers = <NSArray: 0x8d78a70>; layer = <CALayer: 0x8d7bcd0>> | | <UINavigationTransitionView: 0x8d813f0; frame = (0 0; 320 480); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x8d814d0>> | | | <UIViewControllerWrapperView: 0x8d61050; frame = (0 0; 320 480); autoresize = W+H; userInteractionEnabled = NO; layer = <CALayer: 0x8d88f40>> | | | | <UIView: 0x8ab0dc0; frame = (0 0; 320 480); autoresize = RM+BM; layer = <CALayer: 0x8ab0610>> | | | | | <_UILayoutGuide: 0x8ab0e20; frame = (0 0; 0 64); hidden = YES; layer = <CALayer: 0x8ab0e90>> | | | | | <_UILayoutGuide: 0x8ab1080; frame = (0 480; 0 0); hidden = YES; layer = <CALayer: 0x8ab10f0>> | | <UINavigationBar: 0x8d75c40; frame = (0 20; 320 44); opaque = NO; autoresize = W; userInteractionEnabled = NO; gestureRecognizers = <NSArray: 0x8d5e750>; layer = <CALayer: 0x8d70f00>> | | | <_UINavigationBarBackground: 0x8d59af0; frame = (0 -20; 320 64); opaque = NO; autoresize = W; userInteractionEnabled = NO; layer = <CALayer: 0x8d549f0>> - (null) | | | | <_UIBackdropView: 0x8d7c440; frame = (0 0; 320 64); opaque = NO; autoresize = W+H; userInteractionEnabled = NO; layer = <_UIBackdropViewLayer: 0x8d7e7b0>> | | | | | <_UIBackdropEffectView: 0x8d7f1c0; frame = (0 0; 320 64); clipsToBounds = YES; opaque = NO; autoresize = W+H; userInteractionEnabled = NO; animations = { filters.colorMatrix.inputColorMatrix=<CABasicAnimation: 0x8ba4490>; }; layer = <CABackdropLayer: 0x8d7f480>> | | | | | <UIView: 0x8d7fc80; frame = (0 0; 320 64); hidden = YES; opaque = NO; autoresize = W+H; userInteractionEnabled = NO; layer = <CALayer: 0x8d7fce0>> | | | | <UIImageView: 0x8d67cc0; frame = (0 64; 320 0.5); userInteractionEnabled = NO; layer = <CALayer: 0x8d67d50>> - (null) | | | <UINavigationItemView: 0x8ab6400; frame = (124 8; 163 27); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x8ab6480>> | | | | <UILabel: 0x8ab64b0; frame = (0 3; 163 22); text = 'A Story About a Fish'; clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x8ab6550>> | | | <UINavigationItemButtonView: 0x8ab6c80; frame = (8 6; 41 30); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x8ab6d60>> | | | | <UILabel: 0x8ab6f10; frame = (-981 -995; 91 22); text = ''; clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x8ab6fb0>> | | | <_UINavigationBarBackIndicatorView: 0x8d87560; frame = (8 12; 12.5 20.5); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x8d87650>> - Back
直接看也許不輕易懂,還須要聯合Xcode的“Debug view Hierarchy”或許是Reveal對象看現實視圖構造:
我們可以看到在UINavigationBar中包括有4個類,它們年夜致的感化是:
_UINavigationBarBackground :(UIImageView)導航欄配景圖(弗成以直接設置圖片)
UINavigationItemView :(UIView)包括顯示導航欄題目
UINavigationItemButtonView :(UIView)包括顯示導航欄左視圖(弗成移除,更改年夜小,色彩,可以隱蔽,決議了點擊區域的年夜小)
_UINavigationBarBackIndicatorView :(UIImageView)導航欄前往按鈕箭頭圖片(弗成以修正圖片)
_UINavigationBarBackIndicatorView就是前往按鈕的箭頭也就是我們須要保存的,UINavigationItemButtonView就是我們須要研討的也是我們後面提到成績的重要緣由地點。再次看看這個對象在掌握台的輸入:
| | | <UINavigationItemButtonView: 0x8ab6c80; frame = (8 6; 41 30); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x8ab6d60>> | | | | <UILabel: 0x8ab6f10; frame = (-981 -995; 91 22); text = ''; clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x8ab6fb0>>
這個UINavigationItemButtonView應當是體系在這個view的draw辦法裡就決議frame,修正frame就觸發needdisplay從新轉變它的frame,是以這個view只會依據其上的label(也就是前往按鈕顯示的文字)的內容變更而轉變寬度其他根本弗成變,我們固然將label的內容設置為空然則這個UINavigationItemButtonView的年夜小卻並沒有轉變同時點擊區域也沒有轉變。從掌握台裡的還可看到這個veiw的userInteractionEnabled屬性為NO,假如說點擊的是這個view,但如今這個view是弗成交互的,只能解釋是真正呼應點擊事宜的是這個view面前的某個控件(視圖構造和代碼裡都沒有發明這個控件)。是以要想處理我之條件到的成績就得應用這個UINavigationItemButtonView,我們可以在viewDidAppear中獲得到UINavigationItemButtonView(假如用遍歷的方法獲得會有一個延遲,由於這個view的地位固定為第三個所以我們就直接獲得便可以了),將其userInteractionEnabled設置為yes而且在這個View上添加手勢tap事宜便可:
UIView *nav_back = [self.navigationController.navigationBar.subviews objectAtIndex:2]; if ([nav_back isKindOfClass:NSClassFromString(@"UINavigationItemButtonView")]) { nav_back.userInteractionEnabled = YES; // UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithtarget:self action:@selector(backAction:)]; // [nav_back addGestureRecognizer:tap]; UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom]; backButton.frame = CGRectMake(0, 0, 20, 21); [backButton addTarget:self action:@selector(customMethod) forControlEvents:UIControlEventTouchUpInside]; [nav_back addSubview:backButton]; }
如許可以轉變前往按鈕的點擊事宜,此時想要處理點擊規模只能在這個view上添加一個指定年夜小的按鈕了。最初總結出來的處理方法就是創立一個viewController的分類:
UIViewController+CustomBackButton.h文件 #import <UIKit/UIKit.h> @interface UIViewController (CustomBackButton) - (void)customNavBackButtonMethod; @end UIViewController+CustomBackButton.m文件 #import "UIViewController+CustomBackButton.h" #import <objc/runtime.h> @implementation UIViewController (CustomBackButton) + (void)load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ Class class = [self class]; SEL originalSelector = @selector(viewDidLoad); SEL swizzledSelector = @selector(mm_viewDidLoad); SEL originalSelector1 = @selector(viewDidAppear:); SEL swizzledSelector1 = @selector(mm_viewDidAppear); Method originalMethod = class_getInstanceMethod(class, originalSelector); Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector); Method originalMethod1 = class_getInstanceMethod(class, originalSelector1); Method swizzledMethod1 = class_getInstanceMethod(class, swizzledSelector1); BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)); BOOL didAddMethod1 = class_addMethod(class, originalSelector1, method_getImplementation(swizzledMethod1), method_getTypeEncoding(swizzledMethod1)); if (didAddMethod) { class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); } else { method_exchangeImplementations(originalMethod, swizzledMethod); } if (didAddMethod1) { class_replaceMethod(class, swizzledSelector1, method_getImplementation(originalMethod1), method_getTypeEncoding(originalMethod1)); } else { method_exchangeImplementations(originalMethod1, swizzledMethod1); } }); } #pragma mark - Method Swizzling - (void)mm_viewDidLoad { [self mm_viewDidLoad]; UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil]; [self.navigationItem setBackBarButtonItem:backButtonItem]; } - (void)mm_viewDidAppear { [self mm_viewDidAppear]; UIView *nav_back = [self.navigationController.navigationBar.subviews objectAtIndex:2]; if ([nav_back isKindOfClass:NSClassFromString(@"UINavigationItemButtonView")]) { nav_back.userInteractionEnabled = YES; // UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithtarget:self action:@selector(backAction:)]; // [nav_back addGestureRecognizer:tap]; UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom]; backButton.frame = CGRectMake(0, 0, 20, 21); [backButton addTarget:self action:@selector(customNavBackButtonMethod) forControlEvents:UIControlEventTouchUpInside]; [nav_back addSubview:backButton]; } } - (void)customNavBackButtonMethod { [self.navigationController popViewControllerAnimated:YES]; } @end
在項目外面創立完今後就會失效。這裡所做的就是在一切的viewController履行viewDidLoad的時刻將前往按鈕的文字置空,在履行viewDidAppear的時刻添加一個自界說的按鈕去呼應pop事宜。假如碰到須要自界說前往事宜我在.h將前往事宜開放出來,只需在對應的viewDidLoad中復寫customNavBackButtonMethod辦法便可以在點擊前往按鈕時履行到你復寫的辦法中了,好了,是否是感到很簡略呢。
【關於iOS導航欄前往按鈕成績的處理辦法】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!