Allow not to use UIImageAsset on iOS 13 (#88)

* Allow not to use UIImageAsset on iOS13

* Use imageWithConfiguration: on iOS 13+

* Add configuration class
This commit is contained in:
Levin Li 2020-07-24 17:32:57 +08:00 коммит произвёл GitHub
Родитель f94228e692
Коммит 5883735aa9
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
19 изменённых файлов: 288 добавлений и 132 удалений

Просмотреть файл

@ -53,8 +53,14 @@
8CDA62A52366DAA9004895B5 /* DMDynamicColor.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CDA628B2366DAA9004895B5 /* DMDynamicColor.h */; settings = {ATTRIBUTES = (Public, ); }; };
8CE066CF239E5582002CE16D /* UIColor+DarkModeKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CC8D86C2398E4EC0043276A /* UIColor+DarkModeKit.m */; };
8CE066D0239E5586002CE16D /* UIImage+DarkModeKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CC8D8722398E7A30043276A /* UIImage+DarkModeKit.m */; };
EA1BAF6724C581C5006E755F /* UIView+DarkModeKitSwizzling.h in Headers */ = {isa = PBXBuildFile; fileRef = EA1BAF6524C581C5006E755F /* UIView+DarkModeKitSwizzling.h */; };
EA1BAF6824C581C5006E755F /* UIView+DarkModeKitSwizzling.m in Sources */ = {isa = PBXBuildFile; fileRef = EA1BAF6624C581C5006E755F /* UIView+DarkModeKitSwizzling.m */; };
EA1BAF6F24C58447006E755F /* UIImage+DarkModeKitSwizzling.h in Headers */ = {isa = PBXBuildFile; fileRef = EA1BAF6D24C58447006E755F /* UIImage+DarkModeKitSwizzling.h */; };
EA1BAF7024C58447006E755F /* UIImage+DarkModeKitSwizzling.m in Sources */ = {isa = PBXBuildFile; fileRef = EA1BAF6E24C58447006E755F /* UIImage+DarkModeKitSwizzling.m */; };
EA2EA50024A1CBF2001AE312 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA2EA4FE24A1CAD5001AE312 /* SceneDelegate.swift */; };
EA7316F1248F5055009AE037 /* UILabelVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7316EF248F5050009AE037 /* UILabelVC.swift */; };
EAC41E2F24CADD6E0033C9AC /* DMEnvironmentConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = EAC41E2D24CADD6E0033C9AC /* DMEnvironmentConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; };
EAC41E3024CADD6E0033C9AC /* DMEnvironmentConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = EAC41E2E24CADD6E0033C9AC /* DMEnvironmentConfiguration.m */; };
EAE6065624A9DA1B001304D1 /* UIImageViewVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAE6065324A9D9E0001304D1 /* UIImageViewVC.swift */; };
/* End PBXBuildFile section */
@ -148,8 +154,14 @@
8CDA62892366DAA9004895B5 /* DMDynamicImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DMDynamicImage.m; sourceTree = "<group>"; };
8CDA628A2366DAA9004895B5 /* DarkModeManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DarkModeManager.swift; sourceTree = "<group>"; };
8CDA628B2366DAA9004895B5 /* DMDynamicColor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DMDynamicColor.h; sourceTree = "<group>"; };
EA1BAF6524C581C5006E755F /* UIView+DarkModeKitSwizzling.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIView+DarkModeKitSwizzling.h"; sourceTree = "<group>"; };
EA1BAF6624C581C5006E755F /* UIView+DarkModeKitSwizzling.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIView+DarkModeKitSwizzling.m"; sourceTree = "<group>"; };
EA1BAF6D24C58447006E755F /* UIImage+DarkModeKitSwizzling.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIImage+DarkModeKitSwizzling.h"; sourceTree = "<group>"; };
EA1BAF6E24C58447006E755F /* UIImage+DarkModeKitSwizzling.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIImage+DarkModeKitSwizzling.m"; sourceTree = "<group>"; };
EA2EA4FE24A1CAD5001AE312 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
EA7316EF248F5050009AE037 /* UILabelVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UILabelVC.swift; sourceTree = "<group>"; };
EAC41E2D24CADD6E0033C9AC /* DMEnvironmentConfiguration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DMEnvironmentConfiguration.h; sourceTree = "<group>"; };
EAC41E2E24CADD6E0033C9AC /* DMEnvironmentConfiguration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DMEnvironmentConfiguration.m; sourceTree = "<group>"; };
EAE6065324A9D9E0001304D1 /* UIImageViewVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIImageViewVC.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -214,6 +226,8 @@
8CDA62732366DAA9004895B5 /* DMDynamicColor.m */,
8CDA62762366DAA9004895B5 /* DMDynamicImage.h */,
8CDA62892366DAA9004895B5 /* DMDynamicImage.m */,
EAC41E2D24CADD6E0033C9AC /* DMEnvironmentConfiguration.h */,
EAC41E2E24CADD6E0033C9AC /* DMEnvironmentConfiguration.m */,
8CDA62712366DAA9004895B5 /* DMTraitCollection.h */,
8CDA62722366DAA9004895B5 /* DMTraitCollection.m */,
8CC8D86F2398E7520043276A /* DMNamespace.h */,
@ -221,8 +235,12 @@
8CC8D86C2398E4EC0043276A /* UIColor+DarkModeKit.m */,
8CC8D8712398E7A30043276A /* UIImage+DarkModeKit.h */,
8CC8D8722398E7A30043276A /* UIImage+DarkModeKit.m */,
EA1BAF6D24C58447006E755F /* UIImage+DarkModeKitSwizzling.h */,
EA1BAF6E24C58447006E755F /* UIImage+DarkModeKitSwizzling.m */,
8CB63E3F238551F3008ABCE2 /* UIView+DarkModeKit.h */,
8CB63E40238551F3008ABCE2 /* UIView+DarkModeKit.m */,
EA1BAF6524C581C5006E755F /* UIView+DarkModeKitSwizzling.h */,
EA1BAF6624C581C5006E755F /* UIView+DarkModeKitSwizzling.m */,
);
path = DarkModeCore;
sourceTree = "<group>";
@ -337,7 +355,10 @@
buildActionMask = 2147483647;
files = (
8CC8D86D2398E4EC0043276A /* UIColor+DarkModeKit.h in Headers */,
EA1BAF6724C581C5006E755F /* UIView+DarkModeKitSwizzling.h in Headers */,
EA1BAF6F24C58447006E755F /* UIImage+DarkModeKitSwizzling.h in Headers */,
8CC8D8702398E7520043276A /* DMNamespace.h in Headers */,
EAC41E2F24CADD6E0033C9AC /* DMEnvironmentConfiguration.h in Headers */,
8CDA628D2366DAA9004895B5 /* DMTraitCollection.h in Headers */,
8CDA628C2366DAA9004895B5 /* FluentDarkModeKit.h in Headers */,
8CB63E41238551F3008ABCE2 /* UIView+DarkModeKit.h in Headers */,
@ -531,9 +552,11 @@
buildActionMask = 2147483647;
files = (
8CDA62972366DAA9004895B5 /* UIScrollView+DarkModeKit.swift in Sources */,
EAC41E3024CADD6E0033C9AC /* DMEnvironmentConfiguration.m in Sources */,
8CB63E42238551F3008ABCE2 /* UIView+DarkModeKit.m in Sources */,
8CDA62A12366DAA9004895B5 /* UITextField+DarkModeKit.swift in Sources */,
8CDA62952366DAA9004895B5 /* UIWindow+DarkModeKit.swift in Sources */,
EA1BAF6824C581C5006E755F /* UIView+DarkModeKitSwizzling.m in Sources */,
8CDA629E2366DAA9004895B5 /* UIViewController+DarkModeKit.swift in Sources */,
8CDA62992366DAA9004895B5 /* UIImageView+DarkModeKit.swift in Sources */,
8CDA62962366DAA9004895B5 /* UIProgressView+DarkModeKit.swift in Sources */,
@ -551,6 +574,7 @@
8CDA62922366DAA9004895B5 /* UIToolbar+DarkModeKit.swift in Sources */,
8CDA629A2366DAA9004895B5 /* UIPageControl+DarkModeKit.swift in Sources */,
8CDA62932366DAA9004895B5 /* UIButton+DarkModeKit.swift in Sources */,
EA1BAF7024C58447006E755F /* UIImage+DarkModeKitSwizzling.m in Sources */,
8CDA629B2366DAA9004895B5 /* UITableView+DarkModeKit.swift in Sources */,
8CDA629F2366DAA9004895B5 /* UILabel+DarkModeKit.swift in Sources */,
);

Просмотреть файл

@ -39,9 +39,8 @@
- (UIImage *)resolvedImage {
if (DMTraitCollection.overrideTraitCollection.userInterfaceStyle == DMUserInterfaceStyleDark) {
return self.darkImage;
} else {
return self.lightImage;
}
return self.lightImage;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
@ -88,6 +87,13 @@
darkImage:[self.darkImage imageWithHorizontallyFlippedOrientation]];
}
- (UIImage *)imageWithConfiguration:(UIImageConfiguration *)configuration API_AVAILABLE(ios(13.0)) {
if (configuration.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
return [_darkImage imageWithConfiguration:configuration];
}
return [_lightImage imageWithConfiguration:configuration];
}
- (id)copy {
return [self copyWithZone:nil];
}

Просмотреть файл

@ -0,0 +1,18 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface DMEnvironmentConfiguration : NSObject
@property (nonatomic) BOOL useImageAsset; // Defaults to NO
- (instancetype)init;
@end
NS_ASSUME_NONNULL_END

Просмотреть файл

@ -0,0 +1,18 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
#import "DMEnvironmentConfiguration.h"
@implementation DMEnvironmentConfiguration
- (instancetype)init {
self = [super init];
if (self) {
_useImageAsset = NO;
}
return self;
}
@end

Просмотреть файл

@ -5,7 +5,7 @@
#import <UIKit/UIKit.h>
@class UITraitCollection;
@class UITraitCollection, DMEnvironmentConfiguration;
NS_ASSUME_NONNULL_BEGIN
@ -35,9 +35,9 @@ typedef NS_ENUM(NSInteger, DMUserInterfaceStyle) {
+ (void)registerWithViewController:(UIViewController *)viewController syncImmediately:(BOOL)syncImmediately animated:(BOOL)animated;
+ (void)unregister;
// MARK: - Swizzling
// TODO: move swizzling to private header
+ (void)swizzleUIScreenTraitCollectionDidChange API_AVAILABLE(ios(13.0));
// MARK: - Setup
// TODO: Move to private header
+ (void)setupEnvironmentWithConfiguration:(DMEnvironmentConfiguration *)configuration;
@end

Просмотреть файл

@ -3,8 +3,10 @@
// Licensed under the MIT License.
//
#import "DMEnvironmentConfiguration.h"
#import "DMTraitCollection.h"
#import "UIView+DarkModeKit.h"
#import "UIView+DarkModeKitSwizzling.h"
#import "UIImage+DarkModeKitSwizzling.h"
@import ObjectiveC;
@ -243,7 +245,7 @@ static BOOL _isObservingNewWindowAddNotification = NO;
}
// MARK: - Swizzling
+ (void)swizzleUIScreenTraitCollectionDidChange {
+ (void)swizzleUIScreenTraitCollectionDidChange API_AVAILABLE(ios(13.0)) {
static dispatch_once_t onceToken;
__weak typeof(self) weakSelf = self;
dispatch_once(&onceToken, ^{
@ -258,6 +260,24 @@ static BOOL _isObservingNewWindowAddNotification = NO;
});
}
+ (void)setupEnvironmentWithConfiguration:(DMEnvironmentConfiguration *)configuration {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (@available(iOS 13.0, *)) {
[DMTraitCollection swizzleUIScreenTraitCollectionDidChange];
[UIView swizzleTraitCollectionDidChangeToDMTraitCollectionDidChange];
[UIViewController swizzleTraitCollectionDidChangeToDMTraitCollectionDidChange];
if (!configuration.useImageAsset)
[UIImage dm_swizzleIsEqual];
}
else {
[UIView dm_swizzleSetTintColor];
[UIView dm_swizzleSetBackgroundColor];
[UIImage dm_swizzleIsEqual];
}
});
}
@end
@interface UIScreen (DMTraitEnvironment) <DMTraitEnvironment>

Просмотреть файл

@ -5,6 +5,7 @@
#import <FluentDarkModeKit/DMDynamicColor.h>
#import <FluentDarkModeKit/DMDynamicImage.h>
#import <FluentDarkModeKit/DMEnvironmentConfiguration.h>
#import <FluentDarkModeKit/DMTraitCollection.h>
#import <FluentDarkModeKit/UIColor+DarkModeKit.h>
#import <FluentDarkModeKit/UIImage+DarkModeKit.h>

Просмотреть файл

@ -14,8 +14,6 @@ NS_ASSUME_NONNULL_BEGIN
@interface UIImage (DarkModeKit)
+ (void)dm_swizzleIsEqual;
+ (UIImage *)dm_imageWithLightImage:(UIImage *)lightImage darkImage:(UIImage *)darkImage
NS_SWIFT_UNAVAILABLE("Use init(_:light:dark:) instead.");

Просмотреть файл

@ -4,6 +4,7 @@
//
#import "UIImage+DarkModeKit.h"
#import "UIImage+DarkModeKitSwizzling.h"
#import "DMDynamicImage.h"
#import "DMTraitCollection.h"
@ -11,46 +12,23 @@
@implementation UIImage (DarkModeKit)
+ (void)dm_swizzleIsEqual {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SEL selector = @selector(isEqual:);
Method method = class_getInstanceMethod(self, selector);
if (!method)
NSAssert(NO, @"Method not found for [UIImage isEqual:]");
IMP imp = method_getImplementation(method);
class_replaceMethod(self, selector, imp_implementationWithBlock(^BOOL(UIImage *self, UIImage *other) {
/// On iOS 13, UIImage `isEqual:` somehow changes internally and doesn't work for `NSProxy`,
/// here we forward the message to internal images manually
UIImage *realSelf = self;
UIImage *realOther = other;
if (object_getClass(self) == DMDynamicImageProxy.class) {
realSelf = ((DMDynamicImageProxy *)self).resolvedImage;
}
if (object_getClass(other) == DMDynamicImageProxy.class) {
realOther = ((DMDynamicImageProxy *)other).resolvedImage;
}
return ((BOOL(*)(UIImage *, SEL, UIImage *))imp)(realSelf, selector, realOther);
}), method_getTypeEncoding(method));
});
}
+ (UIImage *)dm_imageWithLightImage:(UIImage *)lightImage darkImage:(UIImage *)darkImage {
if (@available(iOS 13, *)) {
UIImageAsset *imageAsset = [[UIImageAsset alloc] init];
if ([UIImage useUIImageAsset]) {
UIImageAsset *imageAsset = [[UIImageAsset alloc] init];
// Always specify a displayScale otherwise a default of 1.0 is assigned
[imageAsset registerImage:lightImage withTraitCollection:[UITraitCollection traitCollectionWithTraitsFromCollections:@[
[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight],
[UITraitCollection traitCollectionWithDisplayScale:lightImage.scale]
]]];
[imageAsset registerImage:darkImage withTraitCollection:[UITraitCollection traitCollectionWithTraitsFromCollections:@[
[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark],
[UITraitCollection traitCollectionWithDisplayScale:darkImage.scale]
]]];
// Always specify a displayScale otherwise a default of 1.0 is assigned
[imageAsset registerImage:lightImage withTraitCollection:[UITraitCollection traitCollectionWithTraitsFromCollections:@[
[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight],
[UITraitCollection traitCollectionWithDisplayScale:lightImage.scale]
]]];
[imageAsset registerImage:darkImage withTraitCollection:[UITraitCollection traitCollectionWithTraitsFromCollections:@[
[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark],
[UITraitCollection traitCollectionWithDisplayScale:darkImage.scale]
]]];
return [imageAsset imageWithTraitCollection:DMTraitCollection.overrideTraitCollection.uiTraitCollection];
return [imageAsset imageWithTraitCollection:DMTraitCollection.overrideTraitCollection.uiTraitCollection];
}
}
return (UIImage *)[[DMDynamicImageProxy alloc] initWithLightImage:lightImage darkImage:darkImage];

Просмотреть файл

@ -0,0 +1,18 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIImage (DarkModeKitSwizzling)
@property (class, readonly) BOOL useUIImageAsset;
+ (void)dm_swizzleIsEqual;
@end
NS_ASSUME_NONNULL_END

Просмотреть файл

@ -0,0 +1,46 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
#import "UIImage+DarkModeKitSwizzling.h"
#import "DMDynamicImage.h"
@import ObjectiveC;
static BOOL _useUIImageAsset = YES;
@implementation UIImage (DarkModeKitSwizzling)
+ (BOOL)useUIImageAsset {
return _useUIImageAsset;
}
+ (void)dm_swizzleIsEqual {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SEL selector = @selector(isEqual:);
Method method = class_getInstanceMethod(self, selector);
if (!method)
NSAssert(NO, @"Method not found for [UIImage isEqual:]");
IMP imp = method_getImplementation(method);
class_replaceMethod(self, selector, imp_implementationWithBlock(^BOOL(UIImage *self, UIImage *other) {
/// On iOS 13, UIImage `isEqual:` somehow changes internally and doesn't work for `NSProxy`,
/// here we forward the message to internal images manually
UIImage *realSelf = self;
UIImage *realOther = other;
if (object_getClass(self) == DMDynamicImageProxy.class) {
realSelf = ((DMDynamicImageProxy *)self).resolvedImage;
}
if (object_getClass(other) == DMDynamicImageProxy.class) {
realOther = ((DMDynamicImageProxy *)other).resolvedImage;
}
return ((BOOL(*)(UIImage *, SEL, UIImage *))imp)(realSelf, selector, realOther);
}), method_getTypeEncoding(method));
_useUIImageAsset = NO;
});
}
@end

Просмотреть файл

@ -16,9 +16,6 @@ NS_ASSUME_NONNULL_BEGIN
@interface UIView (DarkModeKit) <DMTraitEnvironment>
+ (void)dm_swizzleSetBackgroundColor;
+ (void)dm_swizzleSetTintColor;
- (void)dm_updateDynamicColors API_DEPRECATED("dm_updateDynamicColors is deprecated and will not be called on iOS 13.0, use dmTraitCollectionDidChange: instead", ios(11.0, 13.0));;
- (void)dm_updateDynamicImages API_DEPRECATED("dm_updateDynamicImages is deprecated and will not be called on iOS 13.0, use dmTraitCollectionDidChange: instead", ios(11.0, 13.0));;

Просмотреть файл

@ -4,76 +4,13 @@
//
#import "UIView+DarkModeKit.h"
#import "UIView+DarkModeKitSwizzling.h"
#import "DMDynamicColor.h"
@import ObjectiveC;
@implementation UIView (DarkModeKit)
+ (void)dm_swizzleSetBackgroundColor {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SEL selector = @selector(setBackgroundColor:);
Method method = class_getInstanceMethod(self, selector);
if (!method)
NSAssert(NO, @"Method not found for [UIView setBackgroundColor:]");
IMP imp = method_getImplementation(method);
class_replaceMethod(self, selector, imp_implementationWithBlock(^(UIView *self, UIColor *backgroundColor) {
if ([backgroundColor isKindOfClass:[DMDynamicColor class]]) {
self.dm_dynamicBackgroundColor = (DMDynamicColor *)backgroundColor;
}
else {
self.dm_dynamicBackgroundColor = nil;
}
((void (*)(UIView *, SEL, UIColor *))imp)(self, selector, backgroundColor);
}), method_getTypeEncoding(method));
});
}
+ (void)dm_swizzleSetTintColor {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SEL selector = @selector(setTintColor:);
Method method = class_getInstanceMethod(self, selector);
if (!method)
NSAssert(NO, @"Method not found for [UIView setTintdColor:]");
IMP imp = method_getImplementation(method);
class_replaceMethod(self, selector, imp_implementationWithBlock(^(UIView *self, UIColor *tintColor) {
if ([tintColor isKindOfClass:[DMDynamicColor class]]) {
self.dm_dynamicTintColor = (DMDynamicColor *)tintColor;
}
else {
self.dm_dynamicTintColor = nil;
}
((void (*)(UIView *, SEL, UIColor *))imp)(self, selector, tintColor);
}), method_getTypeEncoding(method));
});
}
- (DMDynamicColor *)dm_dynamicBackgroundColor {
return objc_getAssociatedObject(self, _cmd);
}
- (void)setDm_dynamicBackgroundColor:(DMDynamicColor *)dm_dynamicBackgroundColor {
objc_setAssociatedObject(self,
@selector(dm_dynamicBackgroundColor),
dm_dynamicBackgroundColor,
OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (DMDynamicColor *)dm_dynamicTintColor {
return objc_getAssociatedObject(self, _cmd);
}
- (void)setDm_dynamicTintColor:(DMDynamicColor *)dm_dynamicTintColor {
objc_setAssociatedObject(self,
@selector(dm_dynamicTintColor),
dm_dynamicTintColor,
OBJC_ASSOCIATION_COPY_NONATOMIC);
}
// MARK: - Trait Collection
- (DMTraitCollection *)dmTraitCollection {
if (@available(iOS 13.0, *)) {

Просмотреть файл

@ -0,0 +1,22 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@class DMDynamicColor;
@interface UIView (DarkModeKitSwizzling)
@property (nullable, readonly) DMDynamicColor *dm_dynamicBackgroundColor;
@property (nullable, readonly) DMDynamicColor *dm_dynamicTintColor;
+ (void)dm_swizzleSetBackgroundColor;
+ (void)dm_swizzleSetTintColor;
@end
NS_ASSUME_NONNULL_END

Просмотреть файл

@ -0,0 +1,77 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
#import "UIView+DarkModeKitSwizzling.h"
#import "DMDynamicColor.h"
@import ObjectiveC;
@implementation UIView (DarkModeKitSwizzling)
+ (void)dm_swizzleSetBackgroundColor {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SEL selector = @selector(setBackgroundColor:);
Method method = class_getInstanceMethod(self, selector);
if (!method)
NSAssert(NO, @"Method not found for [UIView setBackgroundColor:]");
IMP imp = method_getImplementation(method);
class_replaceMethod(self, selector, imp_implementationWithBlock(^(UIView *self, UIColor *backgroundColor) {
if ([backgroundColor isKindOfClass:[DMDynamicColor class]]) {
self.dm_dynamicBackgroundColor = (DMDynamicColor *)backgroundColor;
}
else {
self.dm_dynamicBackgroundColor = nil;
}
((void (*)(UIView *, SEL, UIColor *))imp)(self, selector, backgroundColor);
}), method_getTypeEncoding(method));
});
}
+ (void)dm_swizzleSetTintColor {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SEL selector = @selector(setTintColor:);
Method method = class_getInstanceMethod(self, selector);
if (!method)
NSAssert(NO, @"Method not found for [UIView setTintdColor:]");
IMP imp = method_getImplementation(method);
class_replaceMethod(self, selector, imp_implementationWithBlock(^(UIView *self, UIColor *tintColor) {
if ([tintColor isKindOfClass:[DMDynamicColor class]]) {
self.dm_dynamicTintColor = (DMDynamicColor *)tintColor;
}
else {
self.dm_dynamicTintColor = nil;
}
((void (*)(UIView *, SEL, UIColor *))imp)(self, selector, tintColor);
}), method_getTypeEncoding(method));
});
}
- (DMDynamicColor *)dm_dynamicBackgroundColor {
return objc_getAssociatedObject(self, _cmd);
}
- (void)setDm_dynamicBackgroundColor:(DMDynamicColor *)dm_dynamicBackgroundColor {
objc_setAssociatedObject(self,
@selector(dm_dynamicBackgroundColor),
dm_dynamicBackgroundColor,
OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (DMDynamicColor *)dm_dynamicTintColor {
return objc_getAssociatedObject(self, _cmd);
}
- (void)setDm_dynamicTintColor:(DMDynamicColor *)dm_dynamicTintColor {
objc_setAssociatedObject(self,
@selector(dm_dynamicTintColor),
dm_dynamicTintColor,
OBJC_ASSOCIATION_COPY_NONATOMIC);
}
@end

Просмотреть файл

@ -4,6 +4,7 @@
#import "../DMDynamicColor.h"
#import "../DMDynamicImage.h"
#import "../DMEnvironmentConfiguration"
#import "../DMNamespace.h"
#import "../DMTraitCollection.h"
#import "../UIColor+DarkModeKit.h"

Просмотреть файл

@ -11,13 +11,13 @@ import UIKit
public final class DarkModeManager: NSObject {
private static var swizzlingConfigured = false
public class func register(with application: UIApplication, syncImmediately: Bool = false, animated: Bool = false) {
commonSetup()
public class func register(with configuration: DMEnvironmentConfiguration, for application: UIApplication, syncImmediately: Bool = false, animated: Bool = false) {
commonSetup(with: configuration)
DMTraitCollection.register(with: application, syncImmediately: syncImmediately, animated: animated)
}
public class func register(with viewController: UIViewController, syncImmediately: Bool = false, animated: Bool = false) {
commonSetup()
public class func register(with configuration: DMEnvironmentConfiguration, for viewController: UIViewController, syncImmediately: Bool = false, animated: Bool = false) {
commonSetup(with: configuration)
DMTraitCollection.register(with: viewController, syncImmediately: syncImmediately, animated: animated)
}
@ -25,33 +25,27 @@ public final class DarkModeManager: NSObject {
DMTraitCollection.unregister()
}
private class func commonSetup() {
private class func commonSetup(with configuration: DMEnvironmentConfiguration) {
guard !swizzlingConfigured else {
return
}
if #available(iOS 13.0, *) {
DMTraitCollection.swizzleUIScreenTraitCollectionDidChange()
UIView.swizzleTraitCollectionDidChangeToDMTraitCollectionDidChange()
UIViewController.swizzleTraitCollectionDidChangeToDMTraitCollectionDidChange()
}
else {
defer { swizzlingConfigured = true }
DMTraitCollection.setupEnvironment(with: configuration)
guard #available(iOS 13.0, *) else {
// Colors
UIView.swizzleWillMoveToWindowOnce
UIView.dm_swizzleSetBackgroundColor()
UIView.dm_swizzleSetTintColor()
UITextField.swizzleTextFieldWillMoveToWindowOnce
UILabel.swizzleDidMoveToWindowOnce
// Images
UIImage.dm_swizzleIsEqual()
UIImageView.swizzleSetImageOnce
UIImageView.swizzleInitImageOnce
UITabBarItem.swizzleSetImageOnce
UITabBarItem.swizzleSetSelectedImageOnce
return
}
swizzlingConfigured = true
}
// MARK: - Internal

Просмотреть файл

@ -15,7 +15,8 @@ final class AppDelegate: UIResponder, UIApplicationDelegate {
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
DarkModeManager.register(with: application)
let configuration = DMEnvironmentConfiguration()
DarkModeManager.register(with: configuration, for: application)
if #available(iOS 13.0, *) {
return true

Просмотреть файл

@ -9,7 +9,7 @@ import XCTest
final class DarkModeKitTests: XCTestCase {
func testSetBackgroundColorSwizzling() {
UIWindow.appearance().backgroundColor = .white
DarkModeManager.register(with: UIApplication.shared)
DarkModeManager.register(with: DMEnvironmentConfiguration(), for: .shared)
_ = UIWindow()
}
@ -180,7 +180,7 @@ final class DarkModeKitTests: XCTestCase {
}
}
else {
let saved = DMTraitCollection.current
let saved = DMTraitCollection.override
DMTraitCollection.setOverride(DMTraitCollection(userInterfaceStyle: userInterfaceStyle), animated: false)
expression()
DMTraitCollection.setOverride(saved, animated: false)