cdts/xdts-ios 3/TreeHole/CYHResetCode/CYH/QMUIKit/QMUIComponents/QMUIButton/QMUINavigationButton.m

491 lines
22 KiB
Mathematica
Raw Normal View History

2023-07-27 09:20:00 +08:00
/**
* Tencent is pleased to support the open source community by making QMUI_iOS available.
* Copyright (C) 2016-2021 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
*/
//
// QMUINavigationButton.m
// QMUIKit
//
// Created by QMUI Team on 2018/4/9.
//
#import "QMUINavigationButton.h"
#import "QMUICore.h"
#import "UIImage+QMUI.h"
#import "UIColor+QMUI.h"
#import "UIViewController+QMUI.h"
#import "QMUINavigationController.h"
#import "UIControl+QMUI.h"
#import "UIView+QMUI.h"
#import "NSString+QMUI.h"
#import "UINavigationController+QMUI.h"
#import "UINavigationItem+QMUI.h"
typedef NS_ENUM(NSInteger, QMUINavigationButtonPosition) {
QMUINavigationButtonPositionNone = -1, // navigationBar使NoneNonealignmentRectInsets
QMUINavigationButtonPositionLeft, // leftBarButtonItemleftBarButtonItemsitem使item使QMUINavigationButtonPositionNone
QMUINavigationButtonPositionRight, // rightBarButtonItemrightBarButtonItemsitem使item使QMUINavigationButtonPositionNone
};
@interface QMUINavigationButton()
@property(nonatomic, assign) QMUINavigationButtonPosition buttonPosition;
@property(nonatomic, strong) UIImage *defaultHighlightedImage;// set normal image normal image alpha highlighted image
@property(nonatomic, strong) UIImage *defaultDisabledImage;// set normal image normal image alpha disabled image
@end
@implementation QMUINavigationButton
- (instancetype)init {
return [self initWithType:QMUINavigationButtonTypeNormal];
}
- (instancetype)initWithType:(QMUINavigationButtonType)type {
return [self initWithType:type title:nil];
}
- (instancetype)initWithType:(QMUINavigationButtonType)type title:(NSString *)title {
if (self = [super initWithFrame:CGRectZero]) {
_type = type;
self.buttonPosition = QMUINavigationButtonPositionNone;
[self setTitle:title forState:UIControlStateNormal];
[self renderButtonStyle];
[self sizeToFit];
}
return self;
}
- (instancetype)initWithImage:(UIImage *)image {
if (self = [self initWithType:QMUINavigationButtonTypeImage]) {
[self setImage:image forState:UIControlStateNormal];
[self sizeToFit];
}
return self;
}
- (void)renderButtonStyle {
UIFont *font = NavBarButtonFont;
if (font) {
self.titleLabel.font = font;
}
self.titleLabel.backgroundColor = UIColorClear;
self.titleLabel.lineBreakMode = NSLineBreakByTruncatingTail;
self.contentMode = UIViewContentModeCenter;
self.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
self.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
self.qmui_automaticallyAdjustTouchHighlightedInScrollView = YES;
// UIBarButtonItem tintColor alwaysTemplate
self.adjustsImageTintColorAutomatically = YES;
if (self.type == QMUINavigationButtonTypeImage) {
// iOS 11 alignmentRectInsetsiOS 10 NO alignmentRectInsets image
self.translatesAutoresizingMaskIntoConstraints = NO;
}
// highlighted disabled UIBarButtonItem alpha UIBarButtonItem UIButton setImage:forState: normal image highlighted image disabled image
self.adjustsImageWhenHighlighted = NO;
self.adjustsImageWhenDisabled = NO;
switch (self.type) {
case QMUINavigationButtonTypeNormal:
break;
case QMUINavigationButtonTypeImage:
// leftBarButtonItems/rightBarButtonItems
self.contentEdgeInsets = UIEdgeInsetsMake(0, 11, 0, 11);
break;
case QMUINavigationButtonTypeBold: {
font = NavBarButtonFontBold;
if (font) {
self.titleLabel.font = font;
}
}
break;
case QMUINavigationButtonTypeBack: {
UIImage *backIndicatorImage = UINavigationBar.qmui_appearanceConfigured.backIndicatorImage;
if (!backIndicatorImage) {
// tintColor
UIColor *tintColor = QMUICMIActivated ? NavBarTintColor : UIColor.qmui_systemTintColor;
backIndicatorImage = [UIImage qmui_imageWithShape:QMUIImageShapeNavBack size:CGSizeMake(13, 23) lineWidth:3 tintColor:tintColor];
}
[self setImage:backIndicatorImage forState:UIControlStateNormal];
[self setImage:[backIndicatorImage qmui_imageWithAlpha:NavBarHighlightedAlpha] forState:UIControlStateHighlighted];
[self setImage:[backIndicatorImage qmui_imageWithAlpha:NavBarDisabledAlpha] forState:UIControlStateDisabled];
self.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
// @warning iOSUIBarButtonItem
UIOffset titleOffsetBaseOnSystem = UIOffsetMake(6, 0);//
UIOffset configurationOffset = NavBarBarBackButtonTitlePositionAdjustment;
self.titleEdgeInsets = UIEdgeInsetsMake(titleOffsetBaseOnSystem.vertical + configurationOffset.vertical, titleOffsetBaseOnSystem.horizontal + configurationOffset.horizontal, -titleOffsetBaseOnSystem.vertical - configurationOffset.vertical, -titleOffsetBaseOnSystem.horizontal - configurationOffset.horizontal);
self.contentEdgeInsets = UIEdgeInsetsMake(0,
0,
0,
self.titleEdgeInsets.left);
}
break;
default:
break;
}
}
- (void)setImage:(UIImage *)image forState:(UIControlState)state {
if (image && self.adjustsImageTintColorAutomatically) {
image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
}
if (image && [self imageForState:state] != image) {
if (state == UIControlStateNormal) {
// normal image highlighted image disabled image
self.defaultHighlightedImage = [[image qmui_imageWithAlpha:NavBarHighlightedAlpha] imageWithRenderingMode:image.renderingMode];
[self setImage:self.defaultHighlightedImage forState:UIControlStateHighlighted];
self.defaultDisabledImage = [[image qmui_imageWithAlpha:NavBarDisabledAlpha] imageWithRenderingMode:image.renderingMode];
[self setImage:self.defaultDisabledImage forState:UIControlStateDisabled];
} else {
// normal image QMUI image state
if (image != self.defaultHighlightedImage && image != self.defaultDisabledImage) {
if ([self imageForState:UIControlStateHighlighted] == self.defaultHighlightedImage && state != UIControlStateHighlighted) {
[self setImage:nil forState:UIControlStateHighlighted];
}
if ([self imageForState:UIControlStateDisabled] == self.defaultDisabledImage && state != UIControlStateDisabled) {
[self setImage:nil forState:UIControlStateDisabled];
}
}
}
}
[super setImage:image forState:state];
}
- (void)setAdjustsImageTintColorAutomatically:(BOOL)adjustsImageTintColorAutomatically {
BOOL valueDifference = _adjustsImageTintColorAutomatically != adjustsImageTintColorAutomatically;
_adjustsImageTintColorAutomatically = adjustsImageTintColorAutomatically;
if (valueDifference) {
[self updateImageRenderingModeIfNeeded];
}
}
- (void)updateImageRenderingModeIfNeeded {
if (self.currentImage) {
NSArray<NSNumber *> *states = @[@(UIControlStateNormal), @(UIControlStateHighlighted), @(UIControlStateSelected), @(UIControlStateSelected|UIControlStateHighlighted), @(UIControlStateDisabled)];
for (NSNumber *number in states) {
UIImage *image = [self imageForState:number.unsignedIntegerValue];
if (!image) {
return;
}
if (self.adjustsImageTintColorAutomatically) {
// setImage: 使 renderingMode image setImage:forState
[self setImage:image forState:[number unsignedIntegerValue]];
} else {
// template 使 template renderingMode original
[self setImage:[image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] forState:[number unsignedIntegerValue]];
}
}
}
}
// navtitle
- (void)tintColorDidChange {
[super tintColorDidChange];
[self setTitleColor:self.tintColor forState:UIControlStateNormal];
[self setTitleColor:[self.tintColor colorWithAlphaComponent:NavBarHighlightedAlpha] forState:UIControlStateHighlighted];
[self setTitleColor:[self.tintColor colorWithAlphaComponent:NavBarDisabledAlpha] forState:UIControlStateDisabled];
}
// UIBarButtonItem iOS 11 image
- (UIEdgeInsets)alignmentRectInsets {
UIEdgeInsets insets = [super alignmentRectInsets];
if (self.type == QMUINavigationButtonTypeNormal || self.type == QMUINavigationButtonTypeBold) {
// iOS
if (self.titleLabel.font.pointSize / 2.0 > 0) {
insets.top = -PixelOne;
insets.bottom = PixelOne;
}
} else if (self.type == QMUINavigationButtonTypeImage) {
// inset UINavigationItem(QMUINavigationButton) position 使
if (self.buttonPosition == QMUINavigationButtonPositionLeft) {
insets.left = 11;
} else if (self.buttonPosition == QMUINavigationButtonPositionRight) {
insets.right = 11;
}
insets.top = 1;
} else if (self.type == QMUINavigationButtonTypeBack) {
insets.top = PixelOne;
}
return insets;
}
@end
@implementation UIBarButtonItem (QMUINavigationButton)
+ (instancetype)qmui_itemWithButton:(QMUINavigationButton *)button target:(nullable id)target action:(nullable SEL)action {
if (!button) return nil;
[button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
return [[self alloc] initWithCustomView:button];
}
+ (instancetype)qmui_itemWithImage:(UIImage *)image target:(nullable id)target action:(nullable SEL)action {
if (!image) return nil;
return [[self alloc] initWithImage:image style:UIBarButtonItemStylePlain target:target action:action];
}
+ (instancetype)qmui_itemWithTitle:(NSString *)title target:(nullable id)target action:(nullable SEL)action {
if (!title) return nil;
return [[self alloc] initWithTitle:title style:UIBarButtonItemStylePlain target:target action:action];
}
+ (instancetype)qmui_itemWithBoldTitle:(NSString *)title target:(nullable id)target action:(nullable SEL)action {
if (!title) return nil;
return [[self alloc] initWithTitle:title style:UIBarButtonItemStyleDone target:target action:action];
}
+ (instancetype)qmui_backItemWithTitle:(nullable NSString *)title target:(nullable id)target action:(nullable SEL)action {
QMUINavigationButton *button = [[QMUINavigationButton alloc] initWithType:QMUINavigationButtonTypeBack title:title];
[button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *barButtonItem = [[self alloc] initWithCustomView:button];
return barButtonItem;
}
+ (instancetype)qmui_backItemWithTarget:(nullable id)target action:(nullable SEL)action {
NSString *backTitle = nil;
if (NeedsBackBarButtonItemTitle) {
backTitle = @"返回"; //
if ([target isKindOfClass:[UIViewController class]]) {
UIViewController *viewController = (UIViewController *)target;
UIViewController *previousViewController = viewController.qmui_previousViewController;
if (previousViewController.navigationItem.backBarButtonItem) {
//
backTitle = previousViewController.navigationItem.backBarButtonItem.title;
} else if ([viewController respondsToSelector:@selector(qmui_backBarButtonItemTitleWithPreviousViewController:)]) {
// QMUI
backTitle = [((UIViewController<QMUINavigationControllerAppearanceDelegate> *)viewController) qmui_backBarButtonItemTitleWithPreviousViewController:previousViewController];
} else if (previousViewController.title) {
//
backTitle = previousViewController.title;
}
}
} else {
backTitle = @" ";
}
return [self qmui_backItemWithTitle:backTitle target:target action:action];
}
+ (instancetype)qmui_closeItemWithTarget:(nullable id)target action:(nullable SEL)action {
UIBarButtonItem *closeItem = [[self alloc] initWithImage:NavBarCloseButtonImage style:UIBarButtonItemStylePlain target:target action:action];
closeItem.accessibilityLabel = @"关闭";
return closeItem;
}
+ (instancetype)qmui_fixedSpaceItemWithWidth:(CGFloat)width {
UIBarButtonItem *item = [[self alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:NULL];
item.width = width;
return item;
}
+ (instancetype)qmui_flexibleSpaceItem {
return [[self alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:NULL];
}
@end
@interface UIBarButtonItem (QMUINavigationButton_Private)
/// UIBarButtonItem QMUINavigationButton
@property(nonatomic, assign, readonly) BOOL qmui_isCustomizedBarButtonItem;
/// UIBarButtonItem QMUINavigationButton
@property(nonatomic, assign, readonly) BOOL qmui_isCustomizedBackBarButtonItem;
/// QMUINavigationButton
@property(nonatomic, strong, readonly) QMUINavigationButton *qmui_navigationButton;
@end
@interface UIViewController (QMUINavigationButton)
@end
@interface UINavigationBar (QMUINavigationButton)
/// UINavigationBar
@property(nonatomic, readonly) BOOL qmui_customizingBackBarButtonItem;
@end
@implementation UIBarButtonItem (QMUINavigationButton_Private)
- (BOOL)qmui_isCustomizedBarButtonItem {
if (!self.customView) {
return NO;
}
return [self.customView isKindOfClass:[QMUINavigationButton class]];
}
- (BOOL)qmui_isCustomizedBackBarButtonItem {
return self.qmui_isCustomizedBarButtonItem && ((QMUINavigationButton *)self.customView).type == QMUINavigationButtonTypeBack;
}
- (QMUINavigationButton *)qmui_navigationButton {
if ([self.customView isKindOfClass:[QMUINavigationButton class]]) {
return (QMUINavigationButton *)self.customView;
}
return nil;
}
@end
@implementation UINavigationItem (QMUINavigationButton)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SEL selectors[] = {
@selector(setLeftBarButtonItem:animated:),
@selector(setLeftBarButtonItems:animated:),
@selector(setRightBarButtonItem:animated:),
@selector(setRightBarButtonItems:animated:),
};
for (NSUInteger index = 0; index < sizeof(selectors) / sizeof(SEL); index++) {
SEL originalSelector = selectors[index];
SEL swizzledSelector = NSSelectorFromString([@"qmui_" stringByAppendingString:NSStringFromSelector(originalSelector)]);
ExchangeImplementations([self class], originalSelector, swizzledSelector);
}
});
}
- (void)qmui_setLeftBarButtonItem:(UIBarButtonItem *)item animated:(BOOL)animated {
[self qmui_setLeftBarButtonItem:item animated:animated];
// position
item.qmui_navigationButton.buttonPosition = QMUINavigationButtonPositionLeft;
}
- (void)qmui_setLeftBarButtonItems:(NSArray<UIBarButtonItem *> *)items animated:(BOOL)animated {
[self qmui_setLeftBarButtonItems:items animated:animated];
// position
for (NSInteger i = 0; i < items.count; i++) {
if (i == 0) {
items[i].qmui_navigationButton.buttonPosition = QMUINavigationButtonPositionLeft;
} else {
items[i].qmui_navigationButton.buttonPosition = QMUINavigationButtonPositionNone;
}
}
}
- (void)qmui_setRightBarButtonItem:(UIBarButtonItem *)item animated:(BOOL)animated {
[self qmui_setRightBarButtonItem:item animated:animated];
// position
item.qmui_navigationButton.buttonPosition = QMUINavigationButtonPositionRight;
}
- (void)qmui_setRightBarButtonItems:(NSArray<UIBarButtonItem *> *)items animated:(BOOL)animated {
[self qmui_setRightBarButtonItems:items animated:animated];
// position
for (NSInteger i = 0; i < items.count; i++) {
if (i == 0) {
items[i].qmui_navigationButton.buttonPosition = QMUINavigationButtonPositionRight;
} else {
items[i].qmui_navigationButton.buttonPosition = QMUINavigationButtonPositionNone;
}
}
}
@end
@implementation UIViewController (QMUINavigationButton)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 使使 VoiceOver iOS 13.4 Full Keyboard Access
OverrideImplementation([UIViewController class], @selector(accessibilityPerformEscape), ^id(__unsafe_unretained Class originClass, SEL originCMD, IMP (^originalIMPProvider)(void)) {
return ^BOOL(UIViewController *selfObject) {
if (selfObject.navigationItem.leftBarButtonItem.qmui_isCustomizedBackBarButtonItem
&& ((QMUINavigationButton *)selfObject.navigationItem.leftBarButtonItem.customView).enabled
&& selfObject.navigationController.qmui_rootViewController != selfObject
&& selfObject.navigationController.interactivePopGestureRecognizer.enabled
&& !UIApplication.sharedApplication.ignoringInteractionEvents) {
[selfObject.navigationController popViewControllerAnimated:YES];
return YES;
}
// call super
BOOL (*originSelectorIMP)(id, SEL);
originSelectorIMP = (BOOL (*)(id, SEL))originalIMPProvider();
BOOL result = originSelectorIMP(selfObject, originCMD);
return result;
};
});
});
}
@end
@implementation UINavigationBar (QMUINavigationButton)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// contentView directionalLayoutMargins.leading使 8
// Xcode11 beta2 view directionalLayoutMargins crash
// -[_UINavigationBarContentView directionalLayoutMargins]
NSString *barContentViewString = [NSString qmui_stringByConcat:@"_", @"UINavigationBar", @"ContentView", nil];
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 -= (navBar.qmui_customizingBackBarButtonItem ? 8 : 0);
return value;
}
return originResult;
};
});
});
}
- (BOOL)qmui_customizingBackBarButtonItem {
if (self.topItem.leftBarButtonItem) {
return self.topItem.leftBarButtonItem.qmui_isCustomizedBackBarButtonItem;
}
return NO;
}
@end