iOS菜鸟联盟

iOS 11 调整导航条按钮的位置失效了。

2018-03-09  本文已影响87人  走向菜鸟的菜鸟

借鉴大神的操作:picyShrimp

项目需求:有一个界面UI的导航栏右侧按钮要紧靠右侧屏幕边缘,在iOS11以下系统采用UIBarButtonSystemItemFixedSpace方式没有问题,但是做iOS11适配时发现,UIBarButtonSystemItemFixedSpace方式无效了!导致右侧按钮和屏幕边缘出现大约20像素的间距!

在iOS11系统之前,我想大部分iOS开发者调整UIBarButtonItem的位置的时候使用的大概都是UIBarButtonSystemItemFixedSpace方式:

UIBarButtonItem *fixedSpace = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
fixedSpace.width = width;
[self.navigationItem setRightBarButtonItems:@[[UIBarButtonItem fixedSpaceWithWidth:-20], rightBarButtonItem]];

iOS 11对导航栏的层级进行了修改,导致这种方式在iOS 11中失效了!
具体解释不再赘述,直接上解决方法。
我们需要做这样的一个分类,我想的是按钮添加在一个我们定义的view中,view作为customView,这样view作为一个位置调整的视图,就可以相对自由的定义位置了

@implementation UINavigationItem (SXFixSpace)

+(void)load {
    [self swizzleInstanceMethodWithOriginSel:@selector(setLeftBarButtonItem:)
                                 swizzledSel:@selector(sx_setLeftBarButtonItem:)];
    [self swizzleInstanceMethodWithOriginSel:@selector(setRightBarButtonItem:)
                                 swizzledSel:@selector(sx_setRightBarButtonItem:)];
}

-(void)sx_setLeftBarButtonItem:(UIBarButtonItem *)leftBarButtonItem{
    if (leftBarButtonItem.customView) {
        if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 11) {
            UIView *customView = leftBarButtonItem.customView;
            BarView *barView = [[BarView alloc]initWithFrame:customView.bounds];
            [barView addSubview:customView];
            customView.center = barView.center;
            [barView setPosition:SXBarViewPositionLeft];
            [self setLeftBarButtonItems:nil];
            [self sx_setLeftBarButtonItem:[[UIBarButtonItem alloc]initWithCustomView:barView]];
        }else {
            [self sx_setLeftBarButtonItem:nil];
            [self setLeftBarButtonItems:@[[UIBarButtonItem fixedSpaceWithWidth:-20], leftBarButtonItem]];
        }
    }else {
        [self setLeftBarButtonItems:nil];
        [self sx_setLeftBarButtonItem:leftBarButtonItem];
    }
}

-(void)sx_setRightBarButtonItem:(UIBarButtonItem *)rightBarButtonItem{
    if (rightBarButtonItem.customView) {
        if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 11) {
            UIView *customView = rightBarButtonItem.customView;
            BarView *barView = [[BarView alloc]initWithFrame:customView.bounds];
            [barView addSubview:customView];
            customView.center = barView.center;
            [barView setPosition:SXBarViewPositionRight];
            [self setRightBarButtonItems:nil];
            [self sx_setRightBarButtonItem:[[UIBarButtonItem alloc]initWithCustomView:barView]];
        } else {
            [self sx_setRightBarButtonItem:nil];
            [self setRightBarButtonItems:@[[UIBarButtonItem fixedSpaceWithWidth:-20], rightBarButtonItem]];
        }
    }else {
        [self setRightBarButtonItems:nil];
        [self sx_setRightBarButtonItem:rightBarButtonItem];
    }
}

@end

在这个view中我们需要做这样的处理:就是遍历view的父视图,当其实UIStackView的时候,我们修改其左右约束,但是仅仅修改的话会造成约束冲突,所以我们还需要提前移除约束冲突的左右约束(如果担心影响问题,不移除没有关系,仅仅是编译器会报约束冲突log,代码洁癖的话会感觉不舒服)

typedef NS_ENUM(NSInteger, SXBarViewPosition) {
    SXBarViewPositionLeft,
    SXBarViewPositionRight
};

@interface BarView : UIView
@property (nonatomic, assign) SXBarViewPosition position;
@property (nonatomic, assign) BOOL applied;
@end

@implementation BarView

- (void)layoutSubviews {
    [super layoutSubviews];
    if (self.applied || [[[UIDevice currentDevice] systemVersion] floatValue]  < 11) return;
    UIView *view = self;
    while (![view isKindOfClass:UINavigationBar.class] && view.superview) {
        view = [view superview];
        if ([view isKindOfClass:UIStackView.class] && view.superview) {
            if (self.position == SXBarViewPositionLeft) {
                for (NSLayoutConstraint *constraint in view.superview.constraints) {
                    if ([constraint.firstItem isKindOfClass:[UILayoutGuide class]] &&
                     constraint.firstAttribute == NSLayoutAttributeTrailing) {
                        [view.superview removeConstraint:constraint];
                    }
                }
                [view.superview addConstraint:[NSLayoutConstraint constraintWithItem:view
                                                                           attribute:NSLayoutAttributeLeading
                                                                           relatedBy:NSLayoutRelationEqual
                                                                              toItem:view.superview
                                                                           attribute:NSLayoutAttributeLeading
                                                                          multiplier:1.0
                                                                            constant:0]];
                self.applied = YES;
            } else if (self.position == SXBarViewPositionRight) {
                for (NSLayoutConstraint *constraint in view.superview.constraints) {
                    if ([constraint.firstItem isKindOfClass:[UILayoutGuide class]] &&
                     constraint.firstAttribute == NSLayoutAttributeLeading) {
                        [view.superview removeConstraint:constraint];
                    }
                }
                [view.superview addConstraint:[NSLayoutConstraint constraintWithItem:view
                                                                           attribute:NSLayoutAttributeTrailing
                                                                           relatedBy:NSLayoutRelationEqual
                                                                              toItem:view.superview
                                                                           attribute:NSLayoutAttributeTrailing
                                                                          multiplier:1.0
                                                                            constant:0]];
                self.applied = YES;
            }
            break;
        }
    }
}

@end
上一篇下一篇

猜你喜欢

热点阅读