1. 程式人生 > >iOS11 導航欄按鈕位置問題的解決------新

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,至於是多少?
這裡寫圖片描述
我用巨集定義的方式設定的,你也可以自定義,或者使用其他的方式確定其大小