About the solution for the IOS navigation bar return button problem _ios

Source: Internet
Author: User
Tags uikit

Recently encountered a question about the return button on the navigation bar, because the previous project is used in the system default return button style so did not want to go to change, then it is necessary to return the button arrow next to remove the text, and the return button click event Redefined. The first attempt to customize the button and then set to Leftbarbuttonitem, but the picture may not be the same as the system, and the return button is the location of the system itself. Later looked for some information, found that the text removed relatively simple, the general practice is to add the following code controller, and then his next level of control there is a only arrow no text return button:

Copy Code code as follows:
Uibarbuttonitem *backbtn = [[Uibarbuttonitem alloc] initwithtitle:@ "" Style:uibarbuttonitemstyleplain Target:nil Action:nil];
Self.navigationItem.backBarButtonItem = backbtn;

You can also create a root controller that uses the above code and then lets other controllers inherit the root controller to implement bulk operations. But if you encounter a click event that requires a custom return, it is not feasible to add target and action in the above method, and this practice also creates the problem that the actual return button click area is always larger than the button to see, usually 30 distance from the right arrow is clickable. Next, I will take you to understand the causes of these problems and how to solve them better.

First, let's take a look at the hierarchy of the navigation bar view after returning the button text, as shown in the above code, because the view of the navigation bar is loaded and initialized differently than Viewcontroller's. Can not be veiwdidload to observe (viewwillappear) to be in the viewdidload to see the complete navigation bar view hierarchy. We can break a breakpoint in a viewdidload with a return button controller with the text removed and execute it on the console:

PO [[UIWindow Keywindow] recursivedescription]
will get the following output:

<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

Looking directly may not be easy to understand, you also need to combine the Xcode "Debug view hierarchy" or the reveal tool to see the actual view structure:

We can see that there are 4 classes in the Uinavigationbar, and their approximate effect is:

_uinavigationbarbackground : (uiimageview) navigation bar background (no pictures can be set directly)
uinavigationitemview : (uiview) contains display navigation bar title
uinavigationitembuttonview : (uiview) contains display navigation bar left view (not removable, change size, color, can be hidden, determines the size of the click area)
_uinavigationbarbackindicatorview : (uiimageview) navigation bar return button arrow picture (can not modify the picture)
_uinavigationbarbackindicatorview is the arrow that returns the button that we need to keep, uinavigationitembuttonview is what we need to study and the main reason why we mentioned the problem earlier. Again look at the output of this object in the console:

 | | | <UINavigationItemButtonView:0x8ab6c80; frame = (8 6; 41 30); opaque = NO; userinteractionenabled = NO; Layer = <CALayer:0x8ab6d60>> | | | | |
 <UILabel:0x8ab6f10; frame = ( -981-995); text = '; Clipstob Ounds = YES; opaque = NO; userinteractionenabled = NO; Layer = <CALayer:0x8ab6fb0>>

The Uinavigationitembuttonview should be the system that determines the frame in the view's draw method, and the change frame triggers the needdisplay to change its frame again, So this view only changes the width according to the contents of the label on it (that is, the text returned by the button), and the rest is basically not variable. Although we set the contents of the label to NULL but the size of the Uinavigationitembuttonview has not changed, the click Area has not changed. From the console, you can see that the Userinteractionenabled property of this veiw is no, and if you click on this view, now this view is not interactive, The only thing that really responds to the Click event is a control behind this view (the control is not found in the view structure and in the code). So to solve the problem I mentioned earlier, I had to use this uinavigationitembuttonview, We can get to Uinavigationitembuttonview in Viewdidappear (if we use traversal to get a delay, because this view position is fixed to the third so we can get it directly), Set its userinteractionenabled to Yes and add a gesture tap event on this view:

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,);
  [Backbutton addtarget:self Action: @selector (Custommethod) forcontrolevents:uicontroleventtouchupinside];
  [Nav_back Addsubview:backbutton];
 }

This allows you to change the click event of the Return button, and you can only add a button of the specified size to this view when you want to resolve the click Range. The final solution is to create a viewcontroller category:

Uiviewcontroller+custombackbutton.h file #import <UIKit/UIKit.h> @interface Uiviewcontroller (Custombackbutton)-

(void) Customnavbackbuttonmethod; @end uiviewcontroller+custombackbutton.m file #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), ME
  Thod_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

The

will take effect after it has been created in the project. What's done here is to empty the text of the return button when all the Viewcontroller execute viewdidload, and add a custom button to respond to pop events when performing viewdidappear. If you encounter a need to customize the return event, I will open the return event in. h, as long as the Customnavbackbuttonmethod method in the corresponding viewdidload can be performed to the method of your replication when you click the return button, OK, isn't it a simple feeling?

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.