Swizzle using block (#71)
* swizzle-with-block * Fix UILabel * Returning IMP from method_getImplementation and add UILabelVC * Remove NSObject+DarkModeKit
This commit is contained in:
Родитель
8e52a4812d
Коммит
facaafc73d
|
@ -7,8 +7,6 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
8C071AEC23683BF5001AB7B2 /* NSObject+DarkModeKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C071AEA23683BF5001AB7B2 /* NSObject+DarkModeKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8C071AED23683BF5001AB7B2 /* NSObject+DarkModeKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C071AEB23683BF5001AB7B2 /* NSObject+DarkModeKit.m */; };
|
||||
8C1915D82361EFDB004A606A /* FluentDarkModeKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C1915CE2361EFDB004A606A /* FluentDarkModeKit.framework */; };
|
||||
8C1915DD2361EFDB004A606A /* DarkModeKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C1915DC2361EFDB004A606A /* DarkModeKitTests.swift */; };
|
||||
8C63F64323A36B2700D93CF4 /* UIButtonVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C63F64123A36B0900D93CF4 /* UIButtonVC.swift */; };
|
||||
|
@ -56,6 +54,7 @@
|
|||
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 */; };
|
||||
EA7316F1248F5055009AE037 /* UILabelVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7316EF248F5050009AE037 /* UILabelVC.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
|
@ -97,8 +96,6 @@
|
|||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
8C071AEA23683BF5001AB7B2 /* NSObject+DarkModeKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSObject+DarkModeKit.h"; sourceTree = "<group>"; };
|
||||
8C071AEB23683BF5001AB7B2 /* NSObject+DarkModeKit.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSObject+DarkModeKit.m"; sourceTree = "<group>"; };
|
||||
8C1915CE2361EFDB004A606A /* FluentDarkModeKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FluentDarkModeKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
8C1915D22361EFDB004A606A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
8C1915D72361EFDB004A606A /* FluentDarkModeKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FluentDarkModeKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
@ -151,6 +148,7 @@
|
|||
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>"; };
|
||||
EA7316EF248F5050009AE037 /* UILabelVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UILabelVC.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -216,8 +214,6 @@
|
|||
8CDA62892366DAA9004895B5 /* DMDynamicImage.m */,
|
||||
8CDA62712366DAA9004895B5 /* DMTraitCollection.h */,
|
||||
8CDA62722366DAA9004895B5 /* DMTraitCollection.m */,
|
||||
8C071AEA23683BF5001AB7B2 /* NSObject+DarkModeKit.h */,
|
||||
8C071AEB23683BF5001AB7B2 /* NSObject+DarkModeKit.m */,
|
||||
8CC8D86F2398E7520043276A /* DMNamespace.h */,
|
||||
8CC8D86B2398E4EC0043276A /* UIColor+DarkModeKit.h */,
|
||||
8CC8D86C2398E4EC0043276A /* UIColor+DarkModeKit.m */,
|
||||
|
@ -291,6 +287,7 @@
|
|||
8C7B250A23A22A70002E2558 /* UIActivityIndicatorViewVC.swift */,
|
||||
8C63F64123A36B0900D93CF4 /* UIButtonVC.swift */,
|
||||
8C63F64423A374CF00D93CF4 /* UIPageControlVC.swift */,
|
||||
EA7316EF248F5050009AE037 /* UILabelVC.swift */,
|
||||
8CAFD9DD23715FAB001A63B8 /* Assets.xcassets */,
|
||||
8CAFD9DF23715FAB001A63B8 /* LaunchScreen.storyboard */,
|
||||
8CAFD9E223715FAB001A63B8 /* Info.plist */,
|
||||
|
@ -338,7 +335,6 @@
|
|||
files = (
|
||||
8CC8D86D2398E4EC0043276A /* UIColor+DarkModeKit.h in Headers */,
|
||||
8CC8D8702398E7520043276A /* DMNamespace.h in Headers */,
|
||||
8C071AEC23683BF5001AB7B2 /* NSObject+DarkModeKit.h in Headers */,
|
||||
8CDA628D2366DAA9004895B5 /* DMTraitCollection.h in Headers */,
|
||||
8CDA628C2366DAA9004895B5 /* FluentDarkModeKit.h in Headers */,
|
||||
8CB63E41238551F3008ABCE2 /* UIView+DarkModeKit.h in Headers */,
|
||||
|
@ -551,7 +547,6 @@
|
|||
8CDA629C2366DAA9004895B5 /* UINavigationBar+DarkModeKit.swift in Sources */,
|
||||
8CDA629D2366DAA9004895B5 /* UITabBar+DarkModeKit.swift in Sources */,
|
||||
8CDA62922366DAA9004895B5 /* UIToolbar+DarkModeKit.swift in Sources */,
|
||||
8C071AED23683BF5001AB7B2 /* NSObject+DarkModeKit.m in Sources */,
|
||||
8CDA629A2366DAA9004895B5 /* UIPageControl+DarkModeKit.swift in Sources */,
|
||||
8CDA62932366DAA9004895B5 /* UIButton+DarkModeKit.swift in Sources */,
|
||||
8CDA629B2366DAA9004895B5 /* UITableView+DarkModeKit.swift in Sources */,
|
||||
|
@ -582,6 +577,7 @@
|
|||
8C7B250C23A22A80002E2558 /* UIActivityIndicatorViewVC.swift in Sources */,
|
||||
8CAFD9D923715FAA001A63B8 /* ViewController.swift in Sources */,
|
||||
8C63F64323A36B2700D93CF4 /* UIButtonVC.swift in Sources */,
|
||||
EA7316F1248F5055009AE037 /* UILabelVC.swift in Sources */,
|
||||
8CAFD9ED2371606D001A63B8 /* NavigationController.swift in Sources */,
|
||||
8CAFD9D523715FAA001A63B8 /* AppDelegate.swift in Sources */,
|
||||
8C63F64623A374D300D93CF4 /* UIPageControlVC.swift in Sources */,
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
#import "DMDynamicImage.h"
|
||||
#import "DMTraitCollection.h"
|
||||
#import "NSObject+DarkModeKit.h"
|
||||
|
||||
@import ObjectiveC;
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#import <FluentDarkModeKit/DMDynamicColor.h>
|
||||
#import <FluentDarkModeKit/DMDynamicImage.h>
|
||||
#import <FluentDarkModeKit/DMTraitCollection.h>
|
||||
#import <FluentDarkModeKit/NSObject+DarkModeKit.h>
|
||||
#import <FluentDarkModeKit/UIColor+DarkModeKit.h>
|
||||
#import <FluentDarkModeKit/UIImage+DarkModeKit.h>
|
||||
#import <FluentDarkModeKit/UIView+DarkModeKit.h>
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSObject (DarkModeKit)
|
||||
|
||||
/// Swizzle two instance methods for class that calls this method.
|
||||
///
|
||||
/// Return NO if any selector cannot find corresponding method.
|
||||
+ (BOOL)dm_swizzleInstanceMethod:(SEL)fromSelector to:(SEL)toSelector;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -1,29 +0,0 @@
|
|||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
//
|
||||
|
||||
#import "NSObject+DarkModeKit.h"
|
||||
|
||||
@import ObjectiveC;
|
||||
|
||||
@implementation NSObject (DarkModeKit)
|
||||
|
||||
+ (BOOL)dm_swizzleInstanceMethod:(SEL)selector1 to:(SEL)selector2 {
|
||||
Method method1 = class_getInstanceMethod(self, selector1);
|
||||
Method method2 = class_getInstanceMethod(self, selector2);
|
||||
|
||||
if (!method1 || !method2) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (class_addMethod(self, selector1, method_getImplementation(method2), method_getTypeEncoding(method2))) {
|
||||
class_replaceMethod(self, selector2, method_getImplementation(method1), method_getTypeEncoding(method1));
|
||||
} else {
|
||||
method_exchangeImplementations(method1, method2);
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
|
@ -14,6 +14,8 @@ 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.");
|
||||
|
||||
|
|
|
@ -5,14 +5,34 @@
|
|||
|
||||
#import "UIImage+DarkModeKit.h"
|
||||
#import "DMDynamicImage.h"
|
||||
#import "NSObject+DarkModeKit.h"
|
||||
|
||||
@import ObjectiveC;
|
||||
|
||||
@implementation UIImage (DarkModeKit)
|
||||
|
||||
+ (void)load {
|
||||
[UIImage dm_swizzleInstanceMethod:@selector(isEqual:) to:@selector(dm_isEqual:)];
|
||||
+ (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 {
|
||||
|
@ -25,18 +45,4 @@
|
|||
return [UIImage dm_imageWithLightImage:lightImage darkImage:darkImage];
|
||||
}
|
||||
|
||||
- (BOOL)dm_isEqual:(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 [realSelf dm_isEqual:realOther];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -10,24 +10,24 @@
|
|||
|
||||
@implementation UIView (DarkModeKit)
|
||||
|
||||
static void (*dm_original_setBackgroundColor)(UIView *, SEL, UIColor *);
|
||||
|
||||
static void dm_setBackgroundColor(UIView *self, SEL _cmd, UIColor *color) {
|
||||
if ([color isKindOfClass:[DMDynamicColor class]]) {
|
||||
self.dm_dynamicBackgroundColor = (DMDynamicColor *)color;
|
||||
} else {
|
||||
self.dm_dynamicBackgroundColor = nil;
|
||||
}
|
||||
dm_original_setBackgroundColor(self, _cmd, color);
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/42677534/swizzling-on-properties-that-conform-to-ui-appearance-selector
|
||||
+ (void)dm_swizzleSetBackgroundColor {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
Method method = class_getInstanceMethod(self, @selector(setBackgroundColor:));
|
||||
dm_original_setBackgroundColor = (void *)method_getImplementation(method);
|
||||
method_setImplementation(method, (IMP)dm_setBackgroundColor);
|
||||
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));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#import "../DMDynamicImage.h"
|
||||
#import "../DMNamespace.h"
|
||||
#import "../DMTraitCollection.h"
|
||||
#import "../NSObject+DarkModeKit.h"
|
||||
#import "../UIColor+DarkModeKit.h"
|
||||
#import "../UIImage+DarkModeKit.h"
|
||||
#import "../UIView+DarkModeKit.h"
|
||||
|
|
|
@ -18,6 +18,7 @@ public final class DarkModeManager: NSObject {
|
|||
UILabel.swizzleDidMoveToWindowOnce
|
||||
|
||||
// Images
|
||||
UIImage.dm_swizzleIsEqual()
|
||||
UIImageView.swizzleSetImageOnce
|
||||
UIImageView.swizzleInitImageOnce
|
||||
UITabBarItem.swizzleSetImageOnce
|
||||
|
|
|
@ -15,23 +15,41 @@ extension UIImageView {
|
|||
}
|
||||
|
||||
static let swizzleSetImageOnce: Void = {
|
||||
if !dm_swizzleInstanceMethod(#selector(setter: image), to: #selector(dm_setImage(_:))) {
|
||||
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UIImageView.self, selector: #selector(setter: image)))
|
||||
let selector = #selector(setter: image)
|
||||
guard let method = class_getInstanceMethod(UIImageView.self, selector) else {
|
||||
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UIImageView.self, selector: selector))
|
||||
return
|
||||
}
|
||||
|
||||
let imp = method_getImplementation(method)
|
||||
class_replaceMethod(UIImageView.self, selector, imp_implementationWithBlock({ (self: UIImageView, image: UIImage?) -> Void in
|
||||
if object_getClass(image) == DMDynamicImageProxy.self {
|
||||
self.dm_dynamicImage = image
|
||||
}
|
||||
else {
|
||||
self.dm_dynamicImage = nil
|
||||
}
|
||||
let oldIMP = unsafeBitCast(imp, to: (@convention(c) (UIImageView, Selector, UIImage?) -> Void).self)
|
||||
oldIMP(self, selector, image)
|
||||
} as @convention(block) (UIImageView, UIImage?) -> Void), method_getTypeEncoding(method))
|
||||
}()
|
||||
|
||||
static let swizzleInitImageOnce: Void = {
|
||||
if !dm_swizzleInstanceMethod(#selector(UIImageView.init(image:)), to: #selector(UIImageView.dm_init(image:))) {
|
||||
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UIImageView.self, selector: #selector(setter: image)))
|
||||
let selector = #selector(UIImageView.init(image:))
|
||||
guard let method = class_getInstanceMethod(UIImageView.self, selector) else {
|
||||
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UIImageView.self, selector: selector))
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
@objc dynamic func dm_init(image: UIImage?) -> UIImageView {
|
||||
if object_getClass(image) == DMDynamicImageProxy.self {
|
||||
dm_dynamicImage = image
|
||||
}
|
||||
return dm_init(image: image)
|
||||
}
|
||||
let imp = method_getImplementation(method)
|
||||
class_replaceMethod(UIImageView.self, selector, imp_implementationWithBlock({ (self: UIImageView, image: UIImage?) -> UIImageView in
|
||||
if object_getClass(image) == DMDynamicImageProxy.self {
|
||||
self.dm_dynamicImage = image
|
||||
}
|
||||
let oldIMP = unsafeBitCast(imp, to: (@convention(c) (UIImageView, Selector, UIImage?) -> UIImageView).self)
|
||||
return oldIMP(self, selector, image)
|
||||
} as @convention(block) (UIImageView, UIImage?) -> UIImageView), method_getTypeEncoding(method))
|
||||
}()
|
||||
|
||||
override func dm_updateDynamicImages() {
|
||||
super.dm_updateDynamicImages()
|
||||
|
@ -40,14 +58,4 @@ extension UIImageView {
|
|||
image = dynamicImage
|
||||
}
|
||||
}
|
||||
|
||||
@objc dynamic func dm_setImage(_ image: UIImage?) {
|
||||
if object_getClass(image) == DMDynamicImageProxy.self {
|
||||
dm_dynamicImage = image
|
||||
}
|
||||
else {
|
||||
dm_dynamicImage = nil
|
||||
}
|
||||
dm_setImage(image)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,9 +9,21 @@ extension UILabel {
|
|||
}
|
||||
|
||||
static let swizzleDidMoveToWindowOnce: Void = {
|
||||
if !dm_swizzleInstanceMethod(#selector(didMoveToWindow), to: #selector(dm_didMoveToWindow)) {
|
||||
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UILabel.self, selector: #selector(didMoveToWindow)))
|
||||
let selector = #selector(didMoveToWindow)
|
||||
guard let method = class_getInstanceMethod(UILabel.self, selector) else {
|
||||
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UILabel.self, selector: selector))
|
||||
return
|
||||
}
|
||||
|
||||
let imp = method_getImplementation(method)
|
||||
class_replaceMethod(UILabel.self, selector, imp_implementationWithBlock({ (self: UILabel) -> Void in
|
||||
let oldIMP = unsafeBitCast(imp, to: (@convention(c) (UILabel, Selector) -> Void).self)
|
||||
oldIMP(self, selector)
|
||||
if self.currentUserInterfaceStyle != DMTraitCollection.current.userInterfaceStyle {
|
||||
self.currentUserInterfaceStyle = DMTraitCollection.current.userInterfaceStyle
|
||||
self.dmTraitCollectionDidChange(nil)
|
||||
}
|
||||
} as @convention(block) (UILabel) -> Void), method_getTypeEncoding(method))
|
||||
}()
|
||||
|
||||
private var currentUserInterfaceStyle: DMUserInterfaceStyle? {
|
||||
|
@ -19,16 +31,14 @@ extension UILabel {
|
|||
set { objc_setAssociatedObject(self, &Constants.currentThemeKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC) }
|
||||
}
|
||||
|
||||
@objc private dynamic func dm_didMoveToWindow() {
|
||||
dm_didMoveToWindow()
|
||||
if currentUserInterfaceStyle != DMTraitCollection.current.userInterfaceStyle {
|
||||
currentUserInterfaceStyle = DMTraitCollection.current.userInterfaceStyle
|
||||
dmTraitCollectionDidChange(nil)
|
||||
}
|
||||
}
|
||||
|
||||
override open func dmTraitCollectionDidChange(_ previousTraitCollection: DMTraitCollection?) {
|
||||
super.dmTraitCollectionDidChange(previousTraitCollection)
|
||||
|
||||
guard #available(iOS 12.0, *) else {
|
||||
// Fix for iOS 11.x
|
||||
updateDynamicColorInAttributedText()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
private func updateDynamicColorInAttributedText() {
|
||||
|
|
|
@ -33,15 +33,43 @@ extension UITabBarItem: DMTraitEnvironment {
|
|||
}
|
||||
|
||||
static let swizzleSetImageOnce: Void = {
|
||||
if !dm_swizzleInstanceMethod(#selector(setter: image), to: #selector(dm_setImage(_:))) {
|
||||
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UITabBarItem.self, selector: #selector(setter: image)))
|
||||
let selector = #selector(setter: image)
|
||||
guard let method = class_getInstanceMethod(UITabBarItem.self, selector) else {
|
||||
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UITabBarItem.self, selector: selector))
|
||||
return
|
||||
}
|
||||
|
||||
let imp = method_getImplementation(method)
|
||||
class_replaceMethod(UITabBarItem.self, selector, imp_implementationWithBlock({ (self: UITabBarItem, image: UIImage?) -> Void in
|
||||
if object_getClass(image) == DMDynamicImageProxy.self {
|
||||
self.dm_dynamicImage = image
|
||||
}
|
||||
else {
|
||||
self.dm_dynamicImage = nil
|
||||
}
|
||||
let oldIMP = unsafeBitCast(imp, to: (@convention(c) (UITabBarItem, Selector, UIImage?) -> Void).self)
|
||||
oldIMP(self, selector, image)
|
||||
} as @convention(block) (UITabBarItem, UIImage?) -> Void), method_getTypeEncoding(method))
|
||||
}()
|
||||
|
||||
static let swizzleSetSelectedImageOnce: Void = {
|
||||
if !dm_swizzleInstanceMethod(#selector(setter: selectedImage), to: #selector(dm_setSelectedImage(_:))) {
|
||||
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UITabBarItem.self, selector: #selector(setter: selectedImage)))
|
||||
let selector = #selector(setter: selectedImage)
|
||||
guard let method = class_getInstanceMethod(UITabBarItem.self, selector) else {
|
||||
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UITabBarItem.self, selector: selector))
|
||||
return
|
||||
}
|
||||
|
||||
let imp = method_getImplementation(method)
|
||||
class_replaceMethod(UITabBarItem.self, selector, imp_implementationWithBlock({ (self: UITabBarItem, image: UIImage?) -> Void in
|
||||
if object_getClass(image) == DMDynamicImageProxy.self {
|
||||
self.dm_dynamicSelectedImage = image
|
||||
}
|
||||
else {
|
||||
self.dm_dynamicSelectedImage = nil
|
||||
}
|
||||
let oldIMP = unsafeBitCast(imp, to: (@convention(c) (UITabBarItem, Selector, UIImage?) -> Void).self)
|
||||
oldIMP(self, selector, image)
|
||||
} as @convention(block) (UITabBarItem, UIImage?) -> Void), method_getTypeEncoding(method))
|
||||
}()
|
||||
|
||||
open func dmTraitCollectionDidChange(_ previousTraitCollection: DMTraitCollection?) {
|
||||
|
@ -58,24 +86,4 @@ extension UITabBarItem: DMTraitEnvironment {
|
|||
}
|
||||
}
|
||||
|
||||
@objc dynamic func dm_setImage(_ image: UIImage?) {
|
||||
if object_getClass(image) == DMDynamicImageProxy.self {
|
||||
dm_dynamicImage = image
|
||||
}
|
||||
else {
|
||||
dm_dynamicImage = nil
|
||||
}
|
||||
dm_setImage(image)
|
||||
}
|
||||
|
||||
@objc dynamic func dm_setSelectedImage(_ image: UIImage?) {
|
||||
if object_getClass(image) == DMDynamicImageProxy.self {
|
||||
dm_dynamicSelectedImage = image
|
||||
}
|
||||
else {
|
||||
dm_dynamicSelectedImage = nil
|
||||
}
|
||||
dm_setSelectedImage(image)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,16 +26,20 @@ extension UITextField {
|
|||
|
||||
/// `UITextField` will not call `super.willMove(toWindow:)` in its implementation, so we need to swizzle it separately.
|
||||
static let swizzleTextFieldWillMoveToWindowOnce: Void = {
|
||||
if !dm_swizzleInstanceMethod(#selector(willMove(toWindow:)), to: #selector(dm_textFieldWillMove(toWindow:))) {
|
||||
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UITextField.self, selector: #selector(willMove(toWindow:))))
|
||||
let selector = #selector(willMove(toWindow:))
|
||||
guard let method = class_getInstanceMethod(UITextField.self, selector) else {
|
||||
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UITextField.self, selector: selector))
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
@objc private dynamic func dm_textFieldWillMove(toWindow window: UIWindow?) {
|
||||
dm_textFieldWillMove(toWindow: window)
|
||||
if window != nil {
|
||||
dm_updateDynamicColors()
|
||||
dm_updateDynamicImages()
|
||||
}
|
||||
}
|
||||
let imp = method_getImplementation(method)
|
||||
class_replaceMethod(UITextField.self, selector, imp_implementationWithBlock({ (self: UITextField, window: UIWindow?) -> Void in
|
||||
let oldIMP = unsafeBitCast(imp, to: (@convention(c) (UITextField, Selector, UIWindow?) -> Void).self)
|
||||
oldIMP(self, selector, window)
|
||||
if window != nil {
|
||||
self.dm_updateDynamicColors()
|
||||
self.dm_updateDynamicImages()
|
||||
}
|
||||
} as @convention(block) (UITextField, UIWindow?) -> Void), method_getTypeEncoding(method))
|
||||
}()
|
||||
}
|
||||
|
|
|
@ -28,18 +28,22 @@ extension UIView: DMTraitEnvironment {
|
|||
|
||||
extension UIView {
|
||||
static let swizzleWillMoveToWindowOnce: Void = {
|
||||
if !dm_swizzleInstanceMethod(#selector(willMove(toWindow:)), to: #selector(dm_willMove(toWindow:))) {
|
||||
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UIView.self, selector: #selector(willMove(toWindow:))))
|
||||
let selector = #selector(willMove(toWindow:))
|
||||
guard let method = class_getInstanceMethod(UIView.self, selector) else {
|
||||
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UIView.self, selector: selector))
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
@objc private dynamic func dm_willMove(toWindow window: UIWindow?) {
|
||||
dm_willMove(toWindow: window)
|
||||
if window != nil {
|
||||
dm_updateDynamicColors()
|
||||
dm_updateDynamicImages()
|
||||
}
|
||||
}
|
||||
let imp = method_getImplementation(method)
|
||||
class_replaceMethod(UIView.self, selector, imp_implementationWithBlock({ (self: UIView, window: UIWindow?) -> Void in
|
||||
let oldIMP = unsafeBitCast(imp, to: (@convention(c) (UIView, Selector, UIWindow?) -> Void).self)
|
||||
oldIMP(self, selector, window)
|
||||
if window != nil {
|
||||
self.dm_updateDynamicColors()
|
||||
self.dm_updateDynamicImages()
|
||||
}
|
||||
} as @convention(block) (UIView, UIWindow?) -> Void), method_getTypeEncoding(method))
|
||||
}()
|
||||
}
|
||||
|
||||
extension UIView {
|
||||
|
@ -48,18 +52,22 @@ extension UIView {
|
|||
}
|
||||
|
||||
static let swizzleSetTintColorOnce: Void = {
|
||||
if !dm_swizzleInstanceMethod(#selector(setter: tintColor), to: #selector(dm_setTintColor)) {
|
||||
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UIView.self, selector: #selector(setter: tintColor)))
|
||||
let selector = #selector(setter: tintColor)
|
||||
guard let method = class_getInstanceMethod(UIView.self, selector) else {
|
||||
assertionFailure(DarkModeManager.messageForSwizzlingFailed(class: UIView.self, selector: selector))
|
||||
return
|
||||
}
|
||||
|
||||
let imp = method_getImplementation(method)
|
||||
class_replaceMethod(UIView.self, selector, imp_implementationWithBlock({ (self: UIView, tintColor: UIColor) -> Void in
|
||||
self.dm_dynamicTintColor = tintColor as? DynamicColor
|
||||
let oldIMP = unsafeBitCast(imp, to: (@convention(c) (UIView, Selector, UIColor) -> Void).self)
|
||||
oldIMP(self, selector, tintColor)
|
||||
} as @convention(block) (UIView, UIColor) -> Void), method_getTypeEncoding(method))
|
||||
}()
|
||||
|
||||
private var dm_dynamicTintColor: DynamicColor? {
|
||||
get { return objc_getAssociatedObject(self, &Constants.dynamicTintColorKey) as? DynamicColor }
|
||||
set { objc_setAssociatedObject(self, &Constants.dynamicTintColorKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC) }
|
||||
}
|
||||
|
||||
@objc private dynamic func dm_setTintColor(_ color: UIColor) {
|
||||
dm_dynamicTintColor = color as? DynamicColor
|
||||
dm_setTintColor(color)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ final class MainViewController: ViewController {
|
|||
Row(name: "UIView", vcType: UIViewVC.self),
|
||||
Row(name: "UIActivityIndicatorView", vcType: UIActivityIndicatorViewVC.self),
|
||||
Row(name: "UIButton", vcType: UIButtonVC.self),
|
||||
Row(name: "UILabel", vcType: UILabelVC.self),
|
||||
Row(name: "UIPageControl", vcType: UIPageControlVC.self)
|
||||
]
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
//
|
||||
|
||||
import FluentDarkModeKit
|
||||
|
||||
final class UILabelVC: ViewController {
|
||||
let label: UILabel = {
|
||||
let label = UILabel()
|
||||
label.text = "Test"
|
||||
label.textColor = UIColor(.dm, light: .red, dark: .green)
|
||||
return label
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
view.backgroundColor = UIColor(.dm, light: .white, dark: .black)
|
||||
|
||||
view.addSubview(label)
|
||||
}
|
||||
|
||||
override func viewDidLayoutSubviews() {
|
||||
super.viewDidLayoutSubviews()
|
||||
|
||||
label.sizeToFit()
|
||||
label.center = view.center
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче