iOS11 導航欄按鈕位置問題的解決------新
iOS11 導航欄按鈕位置問題的解決——新
之前有寫過iOS11導航欄按鈕位置的一篇解決方案,當時的解決思路是針對navigationItem做調整,強制修改約束
具體細節可以跳轉
但是後期發現這個解決方案仍有許多問題
1.介面在push和pop之後約束會失效,當時的解決方案是寫在viewWillAppear中遮蔽,但是這樣就造成了如果使用的話可能會有很多開發者不習慣
2.刪除約束的問題,雖然有強制修改約束,但是針對不同的開發者的應用,約束條件可能會有所變動,所以可能不適應所有方式
3.多個按鈕的設定沒有寫,很多人會出現疑惑
4.偶發的約束失效,或者其他問題
新的思路,
之前有人是修改button的位置偏移或者點選區域等來調整,但是這樣多個按鈕就會出現重疊和按鈕點選區域無效的情況,所以就沒有考慮
至於自定義控制元件,比如自定義bar或者自定義view等不作為考慮物件,此次的目的是修改系統的導航欄
擴充套件系統的導航欄,在系統的導航欄中進行約束調整.
開始的思路是類似之前的寫法.刪除不需要的約束,重新新增新的約束用以限制位置,也確實實現了,但是這樣的方式跟之前仍然是一樣的問題
或造成push和pop的約束丟失
於是想到了layoutMargins這個屬性
我們遍歷圖層大致可以看到這樣的
<_UINavigationBarContentView: 0x7fc141607250; frame = (0 0; 414 44); layer = <CALayer: 0x608000038cc0>>
這個UINavigationBarContentView平鋪在導航欄中作為iOS11的各個按鈕的父檢視,該檢視的所有的子檢視都會有一個layoutMargins被佔用,也就是系統調整的佔位,我們只要把這個置空就行了.那樣的話該檢視下的所有的子檢視的空間就會變成我們想要的那樣,當然為了保險起見,該檢視的父檢視也就是bar的layoutMargins也置空,這樣 整個bar就會跟一個普通檢視一樣了 左右的佔位約束就不存在了
於是就出現了這樣的程式碼
@implementation UINavigationBar (SXFixSpace)
+(void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self swizzleInstanceMethodWithOriginSel:@selector(layoutSubviews)
swizzledSel:@selector(sx_layoutSubviews)];
});
}
-(void )sx_layoutSubviews{
[self sx_layoutSubviews];
if (deviceVersion >= 11) {
self.layoutMargins = UIEdgeInsetsZero;
for (UIView *subview in self.subviews) {
if ([NSStringFromClass(subview.class) containsString:@"ContentView"]) {
subview.layoutMargins = UIEdgeInsetsZero;//可修正iOS11之後的偏移
}
}
}
}
@end
是的,這一次的修正方式何其的輕鬆,之前饒了太多的彎路….
於是在結合iOS11之前的特性,和並出新的解決導航欄按鈕問題的新的解決方案,
這一次,修正的更加徹底
相較於上一次的優勢,
1.可以使用itmes方式設定多個按鈕
2.可以不寫在viewWillAppear中也可以滿足push和pop不更改約束的問題
3.不對約束進行修改,修改的是layoutMargins,使其預設的20變成0,這樣不影響導航欄中其他檢視的約束衝突問題
4.程式碼量不重,和之前不通,這次僅僅是調整layoutMargins,不需要為了修改約束等再新增圖層等,具體可以看我之前的,比較寫法差異
5.最後程式碼也更加簡潔.
@implementation UINavigationBar (SXFixSpace)
+(void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self swizzleInstanceMethodWithOriginSel:@selector(layoutSubviews)
swizzledSel:@selector(sx_layoutSubviews)];
});
}
-(void)sx_layoutSubviews{
[self sx_layoutSubviews];
if (deviceVersion >= 11) {
self.layoutMargins = UIEdgeInsetsZero;
CGFloat space = sx_tempFixSpace !=0 ? sx_tempFixSpace : sx_defaultFixSpace;
for (UIView *subview in self.subviews) {
if ([NSStringFromClass(subview.class) containsString:@"ContentView"]) {
subview.layoutMargins = UIEdgeInsetsMake(0, space, 0, space);//可修正iOS11之後的偏移
break;
}
}
}
}
@end
@implementation UINavigationItem (SXFixSpace)
+(void)load {
[self swizzleInstanceMethodWithOriginSel:@selector(setLeftBarButtonItem:)
swizzledSel:@selector(sx_setLeftBarButtonItem:)];
[self swizzleInstanceMethodWithOriginSel:@selector(setLeftBarButtonItems:)
swizzledSel:@selector(sx_setLeftBarButtonItems:)];
[self swizzleInstanceMethodWithOriginSel:@selector(setRightBarButtonItem:)
swizzledSel:@selector(sx_setRightBarButtonItem:)];
[self swizzleInstanceMethodWithOriginSel:@selector(setRightBarButtonItems:)
swizzledSel:@selector(sx_setRightBarButtonItems:)];
}
-(void)sx_setLeftBarButtonItem:(UIBarButtonItem *)leftBarButtonItem {
if (leftBarButtonItem.customView) {
if (deviceVersion >= 11) {
sx_tempFixSpace = 0;
[self sx_setLeftBarButtonItem:leftBarButtonItem];
} else {
[self setLeftBarButtonItems:@[leftBarButtonItem]];
}
} else {
sx_tempFixSpace = 20;
[self sx_setLeftBarButtonItem:leftBarButtonItem];
}
}
-(void)sx_setLeftBarButtonItems:(NSArray<UIBarButtonItem *> *)leftBarButtonItems {
NSMutableArray *items = [NSMutableArray arrayWithObject:[self fixedSpaceWithWidth:sx_defaultFixSpace-20]];//可修正iOS11之前的偏移
[items addObjectsFromArray:leftBarButtonItems];
[self sx_setLeftBarButtonItems:items];
}
-(void)sx_setRightBarButtonItem:(UIBarButtonItem *)rightBarButtonItem{
if (rightBarButtonItem.customView) {
if (deviceVersion >= 11) {
sx_tempFixSpace = 0;
[self sx_setRightBarButtonItem:rightBarButtonItem];
} else {
[self setRightBarButtonItems:@[rightBarButtonItem]];
}
} else {
sx_tempFixSpace = 20;
[self sx_setRightBarButtonItem:rightBarButtonItem];
}
}
-(void)sx_setRightBarButtonItems:(NSArray<UIBarButtonItem *> *)rightBarButtonItems{
NSMutableArray *items = [NSMutableArray arrayWithObject:[self fixedSpaceWithWidth:sx_defaultFixSpace-20]];//可修正iOS11之前的偏移
[items addObjectsFromArray:rightBarButtonItems];
[self sx_setRightBarButtonItems:items];
}
-(UIBarButtonItem *)fixedSpaceWithWidth:(CGFloat)width {
UIBarButtonItem *fixedSpace = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace
target:nil
action:nil];
fixedSpace.width = width;
return fixedSpace;
}
@end
效果和之前的解決方案几乎一樣,只能說這次是換了思路實現的
可以很明顯的看到間距不是20,至於是多少?
我用巨集定義的方式設定的,你也可以自定義,或者使用其他的方式確定其大小