一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - IOS - 關(guān)于iOS導(dǎo)航欄返回按鈕問題的解決方法

關(guān)于iOS導(dǎo)航欄返回按鈕問題的解決方法

2021-01-18 13:35千葉的博客 IOS

這篇文章主要為大家詳細(xì)介紹了關(guān)于iOS導(dǎo)航欄返回按鈕問題的解決方法,對(duì)iOS自定義backBarButtonItem的點(diǎn)擊事件進(jìn)行介紹,感興趣的小伙伴們可以參考一下

最近遇到一個(gè)關(guān)于導(dǎo)航欄返回按鈕的問題,因?yàn)橹绊?xiàng)目里面都是用的系統(tǒng)默認(rèn)的返回按鈕樣式所以沒有想過要去更改,后來有需要將返回按鈕箭頭旁邊的文字去掉,同時(shí)將該返回按鈕的點(diǎn)擊事件重新定義。一開始嘗試自定義按鈕然后設(shè)置為leftbarbuttonitem,但是這樣圖片可能跟系統(tǒng)自帶的不一樣,還有就是返回按鈕的位置跟系統(tǒng)自帶的不一樣。后來找了一些資料,發(fā)現(xiàn)將文字去掉比較簡(jiǎn)單,一般做法是控制器中添加如下代碼,然后他的下一級(jí)控制就有一個(gè)只有箭頭沒有文字返回按鈕:

 

復(fù)制代碼 代碼如下:
uibarbuttonitem *backbtn = [[uibarbuttonitem alloc] initwithtitle:@"" style:uibarbuttonitemstyleplain target:nil action:nil];
self.navigationitem.backbarbuttonitem = backbtn;


也可以創(chuàng)建一個(gè)根控制器在其中使用上述代碼然后讓其他控制器繼承這個(gè)根控制器實(shí)現(xiàn)批量操作。但是如果遇到需要自定義該返回的點(diǎn)擊事件的時(shí)候,在上面方法中添加target與action是不可行的,同時(shí)這種做法也會(huì)產(chǎn)生一個(gè)問題,就是實(shí)際的返回按鈕點(diǎn)擊區(qū)域總是比按鈕看到的范圍大,一般是距離箭頭右邊30距離都可點(diǎn)擊。接下來我就帶大家一起了解這些問題產(chǎn)生的原因以及如何更好的解決這些問題。

 

  首先我們看一下按照上面代碼去掉返回按鈕文字之后的導(dǎo)航欄視圖的結(jié)構(gòu)層次,因?yàn)閷?dǎo)航欄的視圖加載以及初始化跟viewcontroller的view不一樣,不能再veiwdidload中去觀察(viewwillappear中也不行)要在viewdidload中才可以看到完整的導(dǎo)航欄視圖結(jié)構(gòu)層次。我們可以在一個(gè)有去掉文字的返回按鈕控制器的viewdidload中打上斷點(diǎn)然后在控制臺(tái)執(zhí)行:

po [[uiwindow keywindow] recursivedescription]
會(huì)得到如下輸出:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<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

直接看或許不容易懂,還需要結(jié)合xcode的“debug view hierarchy”或者是reveal工具看實(shí)際視圖結(jié)構(gòu):

關(guān)于iOS導(dǎo)航欄返回按鈕問題的解決方法

我們可以看到在uinavigationbar中包含有4個(gè)類,它們大致的作用是:

_uinavigationbarbackground :(uiimageview)導(dǎo)航欄背景圖(不可以直接設(shè)置圖片)
uinavigationitemview :(uiview)包含顯示導(dǎo)航欄標(biāo)題
uinavigationitembuttonview :(uiview)包含顯示導(dǎo)航欄左視圖(不可移除,更改大小,顏色,可以隱藏,決定了點(diǎn)擊區(qū)域的大小)
_uinavigationbarbackindicatorview :(uiimageview)導(dǎo)航欄返回按鈕箭頭圖片(不可以修改圖片)
_uinavigationbarbackindicatorview就是返回按鈕的箭頭也就是我們需要保留的,uinavigationitembuttonview就是我們需要研究的也是我們前面提到問題的主要原因所在。再次看看這個(gè)對(duì)象在控制臺(tái)的輸出:

?
1
2
| | | <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>>

這個(gè)uinavigationitembuttonview應(yīng)該是系統(tǒng)在這個(gè)view的draw方法里就決定frame,修改frame就觸發(fā)needdisplay重新改變它的frame,因此這個(gè)view只會(huì)根據(jù)其上的label(也就是返回按鈕顯示的文字)的內(nèi)容變化而改變寬度其余基本不可變,我們雖然將label的內(nèi)容設(shè)置為空但是這個(gè)uinavigationitembuttonview的大小卻并沒有改變同時(shí)點(diǎn)擊區(qū)域也沒有改變。從控制臺(tái)里的還可看到這個(gè)veiw的userinteractionenabled屬性為no,如果說點(diǎn)擊的是這個(gè)view,但現(xiàn)在這個(gè)view是不可交互的,只能說明是真正響應(yīng)點(diǎn)擊事件的是這個(gè)view背后的某個(gè)控件(視圖結(jié)構(gòu)和代碼里都沒有發(fā)現(xiàn)這個(gè)控件)。因此要想解決我之前提到的問題就得利用這個(gè)uinavigationitembuttonview,我們可以在viewdidappear中取得到uinavigationitembuttonview(如果用遍歷的方式獲取會(huì)有一個(gè)延遲,因?yàn)檫@個(gè)view的位置固定為第三個(gè)所以我們就直接獲取就可以了),將其userinteractionenabled設(shè)置為yes并且在這個(gè)view上添加手勢(shì)tap事件即可:

?
1
2
3
4
5
6
7
8
9
10
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];
 }

這樣可以改變返回按鈕的點(diǎn)擊事件,此時(shí)想要解決點(diǎn)擊范圍只能在這個(gè)view上添加一個(gè)指定大小的按鈕了。最后總結(jié)出來的解決辦法就是創(chuàng)建一個(gè)viewcontroller的分類:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
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

在項(xiàng)目里面創(chuàng)建完以后就會(huì)生效。這里所做的就是在所有的viewcontroller執(zhí)行viewdidload的時(shí)候?qū)⒎祷匕粹o的文字置空,在執(zhí)行viewdidappear的時(shí)候添加一個(gè)自定義的按鈕去響應(yīng)pop事件。如果遇到需要自定義返回事件我在.h將返回事件開放出來,只要在對(duì)應(yīng)的viewdidload中復(fù)寫customnavbackbuttonmethod方法就可以在點(diǎn)擊返回按鈕時(shí)執(zhí)行到你復(fù)寫的方法中了,好了,是不是感覺很簡(jiǎn)單呢。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 手机看片自拍自自拍日韩免费 | 韩国靠逼| 色天使亚洲综合在线观看 | 9久热久爱免费精品视频在线观看 | 亚洲黄色大片 | 精品人人视屏 | 亚洲一欧洲中文字幕在线 | 91大神在线精品播放 | 国产九九在线 | 性夜影院爽黄A爽免费动漫 性色欲情网站IWWW九文堂 | 国产xx肥老妇视频奂费 | 国产亚洲综合成人91精品 | 欧美贵妇videos办公室 | 男人狂躁女人下半身 | 日本无吗免费一二区 | 日韩精品免费一区二区三区 | 免费的毛片视频 | a级免费在线观看 | 国产精品男人的天堂 | 国产一级毛片潘金莲的奶头 | 亚洲国产精久久久久久久 | 国产精品第四页 | 国模娜娜a4u1546全套 | 大胆国模一区二区三区伊人 | 日本高清免费不卡在线 | 欧美一级特黄刺激大片视频 | 天天综合天天综合色在线 | 性德国高清xxxxbbbb | 成人免费一区二区三区在线观看 | 天天天天天天天操 | 国产在线看片护士免费视频 | 久久久96| 嫩草影院精品视频在线观看 | 99热这里只有精品在线观看 | 公园吃女人奶野战视频 | 色综合视频一区二区观看 | 欧美日韩精品乱国产538 | 人人澡 人人澡碰人人看软件 | 成人在线小视频 | 粗了大了 整进去好爽视频 刺激一区仑乱 | 久久综合视频网站 |