Skip to content

Commit

Permalink
fixed Tencent#264 1. 配置表改为在 App 启动时自动运行;2. 增加 QMUIConfigurationTempla…
Browse files Browse the repository at this point in the history
…teProtocol 用于规定配置表的能力
  • Loading branch information
MoLice committed Jan 8, 2018
1 parent c96c243 commit 1613a08
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 30 deletions.
14 changes: 6 additions & 8 deletions QMUIConfigurationTemplate/QMUIConfigurationTemplate.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,13 @@
#import <Foundation/Foundation.h>

/**
* QMUIConfigurationTemplate 是一份配置表,用于配合 QMUIKit 来管理整个 App 的全局样式,使用方式如下:
* 1. 在 QMUI 项目代码的文件夹里找到 QMUIConfigurationTemplate 目录,把里面所有文件复制到自己项目里。
* 2. 在自己项目的 AppDelegate 里 #import "QMUIConfigurationTemplate.h",然后在 application:didFinishLaunchingWithOptions: 里调用 [QMUIConfigurationTemplate setupConfigurationTemplate],即可让配置表生效。
* 3. 更新 QMUIKit 的版本时,请留意 Release Log 里是否有提醒更新配置表,请尽量保持自己项目里的配置表与 QMUIKit 里的配置表一致,避免遗漏新的属性。
* QMUIConfigurationTemplate 是一份配置表,用于配合 QMUIConfiguration 来管理整个 App 的全局样式,使用方式:
* 在 QMUI 项目代码的文件夹里找到 QMUIConfigurationTemplate 目录,把里面所有文件复制到自己项目里,保证能被编译到即可,不需要在某些地方 import,也不需要手动运行。
*
* @warning 请不要在 + load 方法里调用 QMUIConfigurationTemplate 或 QMUIConfigurationMacros 提供的宏,那个时机太早,可能导致 crash
* @warning 更新 QMUIKit 的版本时,请留意 Release Log 里是否有提醒更新配置表,请尽量保持自己项目里的配置表与 QMUIKit 里的配置表一致,避免遗漏新的属性。
* @warning 配置表的 class 名必须以 QMUIConfigurationTemplate 开头,并且实现 <QMUIConfigurationTemplateProtocol>,因为这两者是 QMUI 识别该 NSObject 是否为一份配置表的条件。
* @warning QMUI 2.3.0 之后,配置表改为自动运行,不需要再在某个地方手动运行了。
*/
@interface QMUIConfigurationTemplate : NSObject

+ (void)setupConfigurationTemplate;
@interface QMUIConfigurationTemplate : NSObject <QMUIConfigurationTemplateProtocol>

@end
11 changes: 9 additions & 2 deletions QMUIConfigurationTemplate/QMUIConfigurationTemplate.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@

@implementation QMUIConfigurationTemplate

+ (void)setupConfigurationTemplate {
#pragma mark - <QMUIConfigurationTemplateProtocol>

- (void)applyConfigurationTemplate {

// === 修改配置值 === //

Expand Down Expand Up @@ -85,7 +87,7 @@ + (void)setupConfigurationTemplate {
QMUICMI.navBarLargeTitleColor = nil; // NavBarLargeTitleColor : UINavigationBar 在大标题模式下的标题颜色,仅在 iOS 11 之后才有效
QMUICMI.navBarLargeTitleFont = nil; // NavBarLargeTitleFont : UINavigationBar 在大标题模式下的标题字体,仅在 iOS 11 之后才有效
QMUICMI.navBarBackButtonTitlePositionAdjustment = UIOffsetZero; // NavBarBarBackButtonTitlePositionAdjustment : 导航栏返回按钮的文字偏移
QMUICMI.navBarBackIndicatorImage = nil; // NavBarBackIndicatorImage : 导航栏的返回按钮的图片
QMUICMI.navBarBackIndicatorImage = nil; // NavBarBackIndicatorImage : 导航栏的返回按钮的图片,图片尺寸需要为(13, 21),如果尺寸不一致则会自动调整,以保证与系统的返回按钮图片布局相同。
QMUICMI.navBarCloseButtonImage = [UIImage qmui_imageWithShape:QMUIImageShapeNavClose size:CGSizeMake(16, 16) tintColor:NavBarTintColor]; // NavBarCloseButtonImage : QMUINavigationButton 用到的 × 的按钮图片

QMUICMI.navBarLoadingMarginRight = 3; // NavBarLoadingMarginRight : QMUINavigationTitleView 里左边 loading 的右边距
Expand Down Expand Up @@ -193,4 +195,9 @@ + (void)setupConfigurationTemplate {
QMUICMI.shouldFixTabBarTransitionBugInIPhoneX = NO; // ShouldFixTabBarTransitionBugInIPhoneX : 是否需要自动修复 iOS 11 下,iPhone X 的设备在 push 界面时,tabBar 会瞬间往上跳的 bug
}

// QMUI 2.3.0 版本里,配置表新增这个方法,返回 YES 表示在 App 启动时要自动应用这份配置表。仅当你的 App 里存在多份配置表时,才需要把除默认配置表之外的其他配置表的返回值改为 NO。
- (BOOL)shouldApplyTemplateAutomatically {
return YES;
}

@end
14 changes: 14 additions & 0 deletions QMUIKit/QMUICore/QMUIConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,19 @@
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

/// 所有配置表都应该实现的 protocol
@protocol QMUIConfigurationTemplateProtocol <NSObject>

@required
/// 应用配置表的设置
- (void)applyConfigurationTemplate;

@optional
/// 当返回 YES 时,启动 App 的时候 QMUIConfiguration 会自动应用这份配置表。但启动 App 时自动应用的配置表最多只允许一份,如果有多份则其他的会被忽略,需要在某些时机手动应用
- (BOOL)shouldApplyTemplateAutomatically;

@end

/**
* 维护项目全局 UI 配置的单例,通过业务项目自己的 QMUIConfigurationTemplate 来为这个单例赋值,而业务代码里则通过 QMUIConfigurationMacros.h 文件里的宏来使用这些值。
*/
Expand Down Expand Up @@ -197,5 +210,6 @@ NS_ASSUME_NONNULL_END

/// 单例对象
+ (instancetype _Nullable )sharedInstance;
- (void)applyInitialTemplate;

@end
58 changes: 39 additions & 19 deletions QMUIKit/QMUICore/QMUIConfiguration.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,13 @@
#import "UIImage+QMUI.h"
#import "NSString+QMUI.h"
#import "UIViewController+QMUI.h"
#import <objc/runtime.h>

@implementation QMUIConfiguration

+ (instancetype)sharedInstance {
static dispatch_once_t pred;
static QMUIConfiguration *sharedInstance = nil;

// 检查是否有在某些类的 +load 方法里调用 QMUICMI,因为在 [QMUIConfiguration init] 方法里会操作到 UI 的东西,例如 [UINavigationBar appearance] xxx 等,这些操作不能太早(+load 里就太早了)执行,否则会 crash,所以加这个检测
//#ifdef DEBUG
// BOOL shouldCheckCallStack = NO;
// if (shouldCheckCallStack) {
// for (NSString *symbol in [NSThread callStackSymbols]) {
// if ([symbol containsString:@" load]"]) {
// NSAssert(NO, @"不应该在 + load 方法里调用 %s", __func__);
// return nil;
// }
// }
// }
//#endif

static QMUIConfiguration *sharedInstance;
dispatch_once(&pred, ^{
sharedInstance = [[QMUIConfiguration alloc] init];
});
Expand All @@ -45,6 +32,39 @@ - (instancetype)init {
return self;
}

static BOOL QMUI_hasAppliedInitialTemplate;
- (void)applyInitialTemplate {
if (QMUI_hasAppliedInitialTemplate) {
return;
}

// 自动寻找并应用模板的解释参照这里 https://github.com/QMUI/QMUI_iOS/issues/264

Protocol *protocol = @protocol(QMUIConfigurationTemplateProtocol);
int numberOfClasses = objc_getClassList(NULL, 0);
if (numberOfClasses > 0) {
Class *classes = (__unsafe_unretained Class *)malloc(sizeof(Class) * numberOfClasses);
numberOfClasses = objc_getClassList(classes, numberOfClasses);
for (int i = 0; i < numberOfClasses; i++) {
Class class = classes[i];
if ([NSStringFromClass(class) hasPrefix:@"QMUIConfigurationTemplate"] && [class conformsToProtocol:protocol]) {
if ([class instancesRespondToSelector:@selector(shouldApplyTemplateAutomatically)]) {
id<QMUIConfigurationTemplateProtocol> template = [[class alloc] init];
if ([template shouldApplyTemplateAutomatically]) {
QMUI_hasAppliedInitialTemplate = YES;
[template applyConfigurationTemplate];
// 只应用第一个 shouldApplyTemplateAutomatically 的主题
break;
}
}
}
}
free(classes);
}

QMUI_hasAppliedInitialTemplate = YES;
}

#pragma mark - 初始化默认值

- (void)initDefaultConfiguration {
Expand Down Expand Up @@ -329,10 +349,10 @@ - (void)setNavBarBackIndicatorImage:(UIImage *)navBarBackIndicatorImage {
CGSize customBackIndicatorImageSize = _navBarBackIndicatorImage.size;
if (!CGSizeEqualToSize(customBackIndicatorImageSize, systemBackIndicatorImageSize)) {
CGFloat imageExtensionVerticalFloat = CGFloatGetCenter(systemBackIndicatorImageSize.height, customBackIndicatorImageSize.height);
_navBarBackIndicatorImage = [_navBarBackIndicatorImage qmui_imageWithSpacingExtensionInsets:UIEdgeInsetsMake(imageExtensionVerticalFloat,
0,
imageExtensionVerticalFloat,
systemBackIndicatorImageSize.width - customBackIndicatorImageSize.width)];
_navBarBackIndicatorImage = [[_navBarBackIndicatorImage qmui_imageWithSpacingExtensionInsets:UIEdgeInsetsMake(imageExtensionVerticalFloat,
0,
imageExtensionVerticalFloat,
systemBackIndicatorImageSize.width - customBackIndicatorImageSize.width)] imageWithRenderingMode:_navBarBackIndicatorImage.renderingMode];
}

navBarAppearance.backIndicatorImage = _navBarBackIndicatorImage;
Expand Down
2 changes: 1 addition & 1 deletion QMUIKit/QMUICore/QMUIConfigurationMacros.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

// 单例的宏

#define QMUICMI [QMUIConfiguration sharedInstance]
#define QMUICMI ({[[QMUIConfiguration sharedInstance] applyInitialTemplate];[QMUIConfiguration sharedInstance];})


#pragma mark - Global Color
Expand Down

0 comments on commit 1613a08

Please sign in to comment.