Knight Watson is a theme managing library, with which an iOS app can easily add functions like Night Version. Benefiting from the runtime of ObjC, Knight Watson can add theme to an instance with simply a suffix following it. Thus, it would save you from many hours of learning unfamiliar new methods.
Add following line to your Podfile
.
pod 'KnightWatson'
The import the headers with one line to where you need it.
#import <KnightWatson/KnightWatson.h>
All magic starts from the suffix knw_themable
, and then what left are only familiar Cocoa methods.
// Configure the instance with values by theme
//
UIView
*view = [[UIView alloc] init];
view.knw_themable.backgroundColor = (id)@{@"daylight": UIColor.whiteColor,
@"night": UIColor.blackColor,};
// Change the theme sometime later
//
KNWThemeContext.defaultThemeContext.theme = @"night";
An argument will be regarded as themed if it conforms to protocol KNWObjectArgument
. Class KNWThemedArgument
is provided with the library as an example. Take a look at how method knw_valueWithThemeContext:
is implemented, so you can implement your own THEMED ARGUMENTS. For example, to make NSDictionary
themed argument:
@interface NSDictionary (KNWObjectArgument) <KNWObjectArgument>
@end
@implementation NSDictionary (KNWObjectArgument)
- (id)knw_valueWithThemeContext:(KNWThemeContext *)context
{
return self[context.theme];
}
@end
Instances of UIImage
are widely used, and may be replaced while switching between themes. Because they consume a lot of memory, we shouldn't keep images for all the themes in memory. Instead, we just keep their names. Take a look at class KNWAUIImage
to understand better.
@implementation KNWAUIImage
- (instancetype)initWithImageNamesByTheme:(NSDictionary *)names
{
if (self = [super init]) {
_imageNamesByTheme = names;
}
return self;
}
- (id)knw_valueWithThemeContext:(KNWThemeContext *)context
{
return [UIImage imageNamed:_imageNamesByTheme[context.theme]];
}
@end
Non-object arguments are supported as well:
UIView
*view = [[UIView alloc] init];
NSDictionary
*framesByTheme =
@{@"theme_a": [NSValue valueWithCGRect:CGRectMake(1., 1., 1., 1.)],
@"theme_b": [NSValue valueWithCGRect:CGRectMake(2., 2., 2., 2.)],};
[view
.knw_themable
.argAtIndex(0, framesByTheme)
setFrame:CGRectZero];
Primitive variables (integer, bool...) and C structs boxed in NSNumber
or NSValue
can be automatically de-boxed. Moreover, you can also implement a class to store non-object arguments in your own way. To archieve this, make the class conform protocol KNWNonObjectArgument
. Take class KNWACGColorRef
as an example:
@implementation KNWACGColorRef
- (instancetype)initWithColorsByTheme:(NSDictionary *)colors {
if (self = [super init]) {
_colorsByTheme = colors;
}
return self;
}
- (void)knw_invocation:(NSInvocation *)invocation
setArgumentAtIndex:(NSUInteger)index
withThemeContext:(KNWThemeContext *)context
{
CGColorRef
color = _colorsByTheme[context.theme].CGColor;
[invocation setArgument:&color
atIndex:index];
}
@end
Sometimes, we just want the value for the current theme instead of its changing with the theme. In that case, we need one more line:
UIView
*view = [[UIView alloc] init];
NSDictionary
*colorsByTheme = @{@"daylight": UIColor.whiteColor,
@"night": UIColor.blackColor,};
[view
.knw_themable
.keepThemable(NO)
setBackgroundColor:(id)colorsByTheme];
Or simply use the convenient suffix (notice that the suffix is replaced with knw_themed
):
view.knw_themed.backgroundColor = (id)@{@"daylight": UIColor.whiteColor,
@"night": UIColor.blackColor,};
KNWThemeContext#theme
is of type id
. So it can be of any class as long as your implementation for KNWObjectArgument
(or KNWNonObjectArgument
) can handle it.
For example, if instances of NSNumber
are used as themes, NSArray
will be able to be passed as themed argument:
KNWThemeContext.defaultThemeContext.theme = @1;
UIButton
*button = [[UIButton alloc] init];
NSArray
*colorsByTheme = @[UIColor.whiteColor, UIColor.blackColor,];
[button.knw_themable setTitleColor:(id)colorsByTheme
forState:UIControlStateNormal];
- [
UIButton
,UILabel
,UIImageView
...] support - [
UIColor
,UIImage
,NSAttributedString
...] support - Mutiple themes support
- Custom theme type support
- Cocoapods support
- Non-object (primitive types, C struct) argument support
- Custom argument implementation support
- Dot expression support
- Multiple threads (multiple theme contexts) support
- Class methods support
- Duplicate registered invocations removal
- Notifications for theme-switching
- Support OS X
- Support Cathage
- Documentation