Skip to content

Commit

Permalink
Fixed Tencent#628 iOS 13 下访问 _UINavigationBarContentView.directionalL…
Browse files Browse the repository at this point in the history
…ayoutMargins 会导致 crash
  • Loading branch information
MoLice committed Jun 25, 2019
1 parent 996fc74 commit 0b5e44b
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 9 deletions.
6 changes: 6 additions & 0 deletions QMUIKit/QMUIComponents/QMUIButton/QMUINavigationButton.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ typedef NS_ENUM(NSUInteger, QMUINavigationButtonType) {
*/
@property(nonatomic, assign, readonly) QMUINavigationButtonType type;

/**
* UIBarButtonItem 默认都是跟随 tintColor 的,所以这里声明是否让图片也是用 AlwaysTemplate 模式
* 默认为 YES
*/
@property(nonatomic, assign) BOOL adjustsImageTintColorAutomatically;

/**
* 导航栏按钮的初始化函数,指定的初始化方法
* @param type 按钮类型
Expand Down
54 changes: 45 additions & 9 deletions QMUIKit/QMUIComponents/QMUIButton/QMUINavigationButton.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#import "QMUINavigationController.h"
#import "QMUILog.h"
#import "UIControl+QMUI.h"
#import "UIView+QMUI.h"

typedef NS_ENUM(NSInteger, QMUINavigationButtonPosition) {
QMUINavigationButtonPositionNone = -1, // 不处于navigationBar最左(右)边的按钮,则使用None。用None则不会在alignmentRectInsets里调整位置
Expand Down Expand Up @@ -69,6 +70,7 @@ - (void)renderButtonStyle {
if (font) {
self.titleLabel.font = font;
}
self.adjustsImageTintColorAutomatically = YES;
self.titleLabel.backgroundColor = UIColorClear;
self.titleLabel.lineBreakMode = NSLineBreakByTruncatingTail;
self.contentMode = UIViewContentModeCenter;
Expand Down Expand Up @@ -134,7 +136,7 @@ - (void)renderButtonStyle {

- (void)setImage:(UIImage *)image forState:(UIControlState)state {
if (image && [self imageForState:state] != image) {
if (image.renderingMode == UIImageRenderingModeAutomatic) {
if (image.renderingMode == UIImageRenderingModeAutomatic && self.adjustsImageTintColorAutomatically) {
// UIBarButtonItem 默认都是跟随 tintColor 的,所以这里让图片也是用 AlwaysTemplate 模式
image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
}
Expand Down Expand Up @@ -576,22 +578,56 @@ + (void)load {
});

// 强制修改 contentView 的 directionalLayoutMargins.leading,在使用自定义返回按钮时减小 8
// if (@available(iOS 11, *)) {
// ExtendImplementationOfVoidMethodWithoutArguments([UINavigationBar class], @selector(layoutSubviews), ^(UINavigationBar *selfObject) {
// UIView *contentView = selfObject.qmui_contentView;
// if (contentView) {
// NSDirectionalEdgeInsets value = contentView.directionalLayoutMargins;
// value.leading = value.trailing - (selfObject.qmui_customizingBackBarButtonItem ? 8 : 0);
// contentView.directionalLayoutMargins = value;
// }
// });
// }

// 强制修改 contentView 的 directionalLayoutMargins.leading,在使用自定义返回按钮时减小 8
// Xcode11 beta2 修改私有 view 的 directionalLayoutMargins 会 crash,换个方式
if (@available(iOS 11, *)) {
ExtendImplementationOfVoidMethodWithoutArguments([UINavigationBar class], @selector(layoutSubviews), ^(UINavigationBar *selfObject) {
UIView *contentView = selfObject.qmui_contentView;
if (contentView) {
NSDirectionalEdgeInsets value = contentView.directionalLayoutMargins;
value.leading = value.trailing - (selfObject.qmui_customizingBackBarButtonItem ? 8 : 0);
contentView.directionalLayoutMargins = value;
}

NSString *barContentViewString = [NSString stringWithFormat:@"_%@Content%@", @"UINavigationBar", @"View"];

OverrideImplementation(NSClassFromString(barContentViewString), @selector(directionalLayoutMargins), ^id(__unsafe_unretained Class originClass, SEL originCMD, IMP (^originalIMPProvider)(void)) {
return ^NSDirectionalEdgeInsets(UIView *selfObject) {

// call super
NSDirectionalEdgeInsets (*originSelectorIMP)(id, SEL);
originSelectorIMP = (NSDirectionalEdgeInsets (*)(id, SEL))originalIMPProvider();
NSDirectionalEdgeInsets originResult = originSelectorIMP(selfObject, originCMD);

// get navbar
UINavigationBar *navBar = nil;
if ([NSStringFromClass([selfObject class]) isEqualToString:barContentViewString] &&
[selfObject.superview isKindOfClass:[UINavigationBar class]]) {
navBar = (UINavigationBar *)selfObject.superview;
}

// change insets
if (navBar) {
NSDirectionalEdgeInsets value = originResult;
value.leading = value.trailing - (navBar.qmui_customizingBackBarButtonItem ? 8 : 0);
return value;
}

return originResult;
};
});
}

});
}

- (UIView *)qmui_contentView {
for (UIView *subview in self.subviews) {
if ([NSStringFromClass(subview.class) containsString:@"ContentView"]) {
if ([NSStringFromClass(subview.class) containsString:@"BarContentView"]) {
return subview;
}
}
Expand Down

0 comments on commit 0b5e44b

Please sign in to comment.