激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

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

服務器之家 - 編程語言 - IOS - 關于iOS導航欄返回按鈕問題的解決方法

關于iOS導航欄返回按鈕問題的解決方法

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

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

最近遇到一個關于導航欄返回按鈕的問題,因為之前項目里面都是用的系統默認的返回按鈕樣式所以沒有想過要去更改,后來有需要將返回按鈕箭頭旁邊的文字去掉,同時將該返回按鈕的點擊事件重新定義。一開始嘗試自定義按鈕然后設置為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]
會得到如下輸出:

?
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

直接看或許不容易懂,還需要結合xcode的“debug view hierarchy”或者是reveal工具看實際視圖結構:

關于iOS導航欄返回按鈕問題的解決方法

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

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

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

這個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事件即可:

?
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];
 }

這樣可以改變返回按鈕的點擊事件,此時想要解決點擊范圍只能在這個view上添加一個指定大小的按鈕了。最后總結出來的解決辦法就是創建一個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

在項目里面創建完以后就會生效。這里所做的就是在所有的viewcontroller執行viewdidload的時候將返回按鈕的文字置空,在執行viewdidappear的時候添加一個自定義的按鈕去響應pop事件。如果遇到需要自定義返回事件我在.h將返回事件開放出來,只要在對應的viewdidload中復寫customnavbackbuttonmethod方法就可以在點擊返回按鈕時執行到你復寫的方法中了,好了,是不是感覺很簡單呢。

延伸 · 閱讀

精彩推薦
  • IOSiOS自定義UICollectionViewFlowLayout實現圖片瀏覽效果

    iOS自定義UICollectionViewFlowLayout實現圖片瀏覽效果

    這篇文章主要介紹了iOS自定義UICollectionViewFlowLayout實現圖片瀏覽效果的相關資料,需要的朋友可以參考下...

    jiangamh8882021-01-11
  • IOSiOS實現控制屏幕常亮不變暗的方法示例

    iOS實現控制屏幕常亮不變暗的方法示例

    最近在工作中遇到了要將iOS屏幕保持常亮的需求,所以下面這篇文章主要給大家介紹了關于利用iOS如何實現控制屏幕常亮不變暗的方法,文中給出了詳細的...

    隨風13332021-04-02
  • IOSiOS中滑動控制屏幕亮度和系統音量(附加AVAudioPlayer基本用法和Masonry簡單使用)

    iOS中滑動控制屏幕亮度和系統音量(附加AVAudioPlayer基本用法和

    這篇文章主要介紹了iOS中滑動控制屏幕亮度和系統音量(附加AVAudioPlayer基本用法和Masonry簡單使用)的相關資料,需要的朋友可以參考下...

    CodingFire13652021-02-26
  • IOSiOS開發技巧之狀態欄字體顏色的設置方法

    iOS開發技巧之狀態欄字體顏色的設置方法

    有時候我們需要根據不同的背景修改狀態欄字體的顏色,下面這篇文章主要給大家介紹了關于iOS開發技巧之狀態欄字體顏色的設置方法,文中通過示例代碼...

    夢想家-mxj8922021-05-10
  • IOSiOS中UILabel實現長按復制功能實例代碼

    iOS中UILabel實現長按復制功能實例代碼

    在iOS開發過程中,有時候會用到UILabel展示的內容,那么就設計到點擊UILabel復制它上面展示的內容的功能,也就是Label長按復制功能,下面這篇文章主要給大...

    devilx12792021-04-02
  • IOS詳解iOS中多個網絡請求的同步問題總結

    詳解iOS中多個網絡請求的同步問題總結

    這篇文章主要介紹了詳解iOS中多個網絡請求的同步問題總結,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧...

    liang199111302021-03-15
  • IOSiOS開發之視圖切換

    iOS開發之視圖切換

    在iOS開發中視圖的切換是很頻繁的,獨立的視圖應用在實際開發過程中并不常見,除非你的應用足夠簡單。在iOS開發中常用的視圖切換有三種,今天我們將...

    執著丶執念5272021-01-16
  • IOSiOS中MD5加密算法的介紹和使用

    iOS中MD5加密算法的介紹和使用

    MD5加密是最常用的加密方法之一,是從一段字符串中通過相應特征生成一段32位的數字字母混合碼。對輸入信息生成唯一的128位散列值(32個字符)。這篇文...

    LYSNote5432021-02-04
主站蜘蛛池模板: 日韩精品中文字幕一区 | 亚洲精品日韩色噜噜久久五月 | 国产成年人在线观看 | 久久久久九九九女人毛片 | 欧美日韩亚洲国产精品 | 国产亚洲区 | 一本色道久久综合狠狠躁篇适合什么人看 | 欧美日韩网站在线观看 | 久久久久久久一区二区 | 97伦理| 沉沦的校花奴性郑依婷c到失禁 | 日日鲁夜夜视频热线播放 | 午夜久久电影 | 午夜精品福利影院 | 91婷婷射 | 永久久久| 最新中文字幕日本 | 一级黄色大片在线观看 | 日产精品久久久一区二区福利 | 欧美日韩在线免费观看 | 精品一区二区三区在线视频 | 91精品国产一区二区三区动漫 | 成人三级电影网址 | 成人毛片视频免费 | 久久国产精品一区 | 懂色粉嫩av久婷啪 | 欧美精品一区二区三区在线 | 精品一区二区三区免费看 | 99精品视频一区二区三区 | 欧美成人激情 | 操操操操网 | 最新中文字幕第一页视频 | 国产午夜精品久久久久久久蜜臀 | 成人精品一区二区 | av噜噜噜噜| 国产精品一区二区三区在线播放 | 一区二区三区四区免费 | 国产成人在线综合 | 国产亚洲精久久久久久蜜臀 | 中文字幕在线观看视频www | 91久久国产露脸精品免费 |