iOS custom Backbarbuttonitem Click events

Source: Internet
Author: User

Recently encountered a question about the navigation bar return button, because the previous item is used in the system default return button style so do not want to change, then you need to return the button arrow next to the text is removed, and the return button to redefine the Click event. The first attempt to customize the button is then set to Leftbarbuttonitem, but the picture may be different from the system, and the return button is not the same as the system itself. Later find some information, found to remove the text is relatively simple, the general practice is to add the following code controller, and then his next level of control there is only an arrow no text Back button:

Uibarbuttonitem *backbtn = [[Uibarbuttonitem alloc] Initwithtitle:@ ""= backbtn;

You can also create a root controller that uses the above code and then let other controllers inherit the root controller to implement bulk operations. However, it is not feasible to add the target and action in the above method when it comes to the need to customize the Click event of the return, and this also creates the problem that the actual return button hit area is always larger than the button's view, usually 30 distance from the right of the arrow is clickable. Next I will take you to understand the causes of these problems and how to better solve these problems.

First, let's take a look at the hierarchy of navigation bar views after removing the return button text from the above code, because the view loading and initializing of the navigation bar is not the same as the Viewcontroller view. No more veiwdidload to observe (not in viewwillappear) to see the complete hierarchy of navigation bar views in viewdidload. We can break a breakpoint in a viewdidload that has a Back button controller with a stripped-down text and then execute it on the console:

will get the following output:

<uiwindow:0x8d6f970; frame = (0 0; the 480); AutoResize = w+h; Gesturerecognizers = <nsarray:0x8d5dbf0>; Layer = <uiwindowlayer:0x8d717d0>> | <uilayoutcontainerview:0x8d7bbf0; frame = (0 0; the 480); AutoResize = w+h; Gesturerecognizers = <nsarray:0x8d78a70>; Layer = <calayer:0x8d7bcd0>> | | <uinavigationtransitionview:0x8d813f0; frame = (0 0; the 480); Clipstobounds = YES; AutoResize = w+h; Layer = <calayer:0x8d814d0>> |    | | <uiviewcontrollerwrapperview:0x8d61050; frame = (0 0; the 480); AutoResize = w+h; userinteractionenabled = NO; Layer = <calayer:0x8d88f40>> |    |    | | <uiview:0x8ab0dc0; frame = (0 0; the 480); AutoResize = RM+BM; Layer = <calayer:0x8ab0610>> |    |    |    | | <_uilayoutguide:0x8ab0e20; frame = (0 0;0  -); hidden = YES; Layer = <calayer:0x8ab0e90>> |    |    |    | | <_uilayoutguide:0x8ab1080; frame = (0 480;0 0); hidden = YES; Layer = <calayer:0x8ab10f0>> | | <uinavigationbar:0x8d75c40; frame = (0  -; the  -); opaque = NO; AutoResize = W; userinteractionenabled = NO; Gesturerecognizers = <nsarray:0x8d5e750>; Layer = <calayer:0x8d70f00>> |    | | <_uinavigationbarbackground:0x8d59af0; frame = (0- -; the  -); opaque = NO; AutoResize = W; userinteractionenabled = NO; Layer = <calayer:0x8d549f0>>-(NULL)   |    |    | | <_uibackdropview:0x8d7c440; frame = (0 0; the  -); opaque = NO; AutoResize = w+h; userinteractionenabled = NO; Layer = <_uibackdropviewlayer:0x8d7e7b0>> |    |    |    | | <_uibackdropeffectview:0x8d7f1c0; frame = (0 0; the  -); Clipstobounds = YES; opaque = NO; AutoResize = w+h; userinteractionenabled = NO; Animations = {filters.colormatrix.inputcolormatrix=<cabasicanimation:0x8ba4490>; }; Layer = <cabackdroplayer:0x8d7f480>> |    |    |    | | <uiview:0x8d7fc80; frame = (0 0; the  -); hidden = YES; opaque = NO; AutoResize = w+h; userinteractionenabled = NO; Layer = <calayer:0x8d7fce0>> |    |    | | <uiimageview:0x8d67cc0; frame = (0  -; the 0.5); userinteractionenabled = NO; Layer = <calayer:0X8D67D50>>-(NULL)   |    | | <uinavigationitemview:0x8ab6400; frame = (124 8;163  -); opaque = NO; userinteractionenabled = NO; Layer = <calayer:0x8ab6480>> |    |    | | <uilabel:0x8ab64b0; frame = (0 3;163  A); Text ='a story about a Fish'; Clipstobounds = YES; opaque = NO; userinteractionenabled = NO; Layer = <calayer:0x8ab6550>> |    | | <uinavigationitembuttonview:0x8ab6c80; frame = (8 6; A  -); opaque = NO; userinteractionenabled = NO; Layer = <calayer:0x8ab6d60>> |    |    | | <uilabel:0X8AB6F10; frame = (-981-995; the  A); Text =''; Clipstobounds = YES; opaque = NO; userinteractionenabled = NO; Layer = <calayer:0x8ab6fb0>> |    | | <_uinavigationbarbackindicatorview:0x8d87560; frame = (8  A;12.5 20.5); opaque = NO; userinteractionenabled = NO; Layer = <calayer:0x8d87650>>-Back

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

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

    • _uinavigationbarbackground: (uiimageview) navigation bar background (you can not set the picture 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 Back button arrow picture (can not modify picture)

_uinavigationbarbackindicatorview is the arrow that returns the button, which is what we need to keep, uinavigationitembuttonview is what we need to study and the main reason we mentioned the problem earlier. Look again 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 -91  22 ); Text =  " ; Clipstobounds = YES; opaque = NO; userinteractionenabled = NO; Layer = <calayer: 0x8ab6fb0  >> 

This uinavigationitembuttonview should be the system in this view draw method to decide frame, modify frame to trigger Needdisplay re-change its frame, So this view will only change the width of the rest based on the contents of the label (that is, the text that is displayed on the Back button). Although we set the content of the label to be empty, the size of the Uinavigationitembuttonview does not change and the click Area does not change. From the console can also see this veiw userinteractionenabled property is no, if the click is the view, but now this view is not interactive, It can only be explained that the real response 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 before, I have to use this uinavigationitembuttonview, We can get to Uinavigationitembuttonview in Viewdidappear (if we get a delay by traversing it, because the view is fixed to a 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 will change the click event of the Return button, at which point you want to resolve the click Range to add a specified size button to the view. The final solution is to create a Viewcontroller classification:

uiviewcontroller+CustomBackButton.h File#import<UIKit/UIKit.h>@interfaceUiviewcontroller (Custombackbutton)- (void) Customnavbackbuttonmethod;@endUiviewcontroller+custombackbutton.m File#import "Uiviewcontroller+custombackbutton.h"#import<objc/runtime.h>@implementationUiviewcontroller (Custombackbutton)+ (void) Load {Staticdispatch_once_t Oncetoken; Dispatch_once (&oncetoken, ^{Classclass= [Selfclass]; 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); }    });}#pragmaMark-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, -, +); [Backbutton addtarget:self Action: @selector (Customnavbackbuttonmethod) forControlEvents:        UIControlEventTouchUpInside];    [Nav_back Addsubview:backbutton]; }}- (void) Customnavbackbuttonmethod {[Self.navigationcontroller popviewcontrolleranimated:yes];}@end

It will take effect after the project is created. What is done here is to empty the text of the return button when all Viewcontroller execute the viewdidload, and add a custom button to respond to the pop event when the viewdidappear is executed. If you encounter a custom return event that needs to be returned, I will return the event in. h to open, as long as the corresponding viewdidload in the Customnavbackbuttonmethod method can be clicked on the back of the button to execute to your method of replication, OK, is not feeling very simple. Of course, in the process of studying this problem is still a lot of I do not understand the place, may be in the use of students when you create a variety of problems, the inconvenience to everyone please understand, at the same time welcome you to put forward valuable suggestions to improve, in this grateful!

iOS custom Backbarbuttonitem Click events

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.