DKNightVersion implementation and dknightversion implementation

Source: Internet
Author: User

DKNightVersion implementation and dknightversion implementation

In fact, many software programs that require heavy reading or watching at night will regard the night mode as a feature required by an App. on the basis of not changing the original architecture or even the original code, adding the night mode elegantly becomes a problem that many applications have to face in the process of development.

It is the driving force of the above things that enables me to think about how to use an elegant and concise method to solve this problem.

DKNightVersion is my solution.

So far, most of the work on this framework has been completed. Maybe it is not perfect yet, but I will continue to maintain this framework, help engineers who suffer from achieving the nighttime model to solve this problemA hard nut to crackRequirement.

Implementation

Now I have time.Water and waterWrite a blog to illustrate how this framework achieves the nighttime model and what features it has.

For a long period of time, I was wondering how to avoid overwriting.UIKitAdd the night mode for the iOS App.objc/runtimeDoes not overwrite meUIKitHope to achieve this goal.

Add to UIKit Control nightColorAttribute

Because we will not subclass the UIKit control and then use@propertyAdd attributes to its subclass. Instead, use the magic Category andobjc/runtimeTo add properties for controls in the UI series.

Useobjc/runtimeI believe many people know how to add attributes to categories and often use them in development. If you do not know them, please refer to here.

DKNightVersion is commonly usedcolorFor example:backgroundColor tintColorAre addednightThe color in the night mode,nightBackgroundColor nightTintColor.

- (UIColor *)nightBackgroundColor {    return objc_getAssociatedObject(self, &nightBackgroundColorKey) ? :self.backgroundColor);}- (void)setNightBackgroundColor:(UIColor *)nightBackgroundColor {    objc_setAssociatedObject(self, &nightBackgroundColorKey, nightBackgroundColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}

We create this attribute to save the color in the night mode. In this way, when the topic of the application is switched to the night modenightColorThe color of attribute storage is assigned to the correspondingcolorBut there is a problem. When the application switches back to the normal mode, we lose the original normal mode.color.

Add normalColorStorage color

To solve this problem, we added another property for the UIKit control.normalColorTo save the color in normal mode.

- (UIColor *)normalBackgroundColor {    return objc_getAssociatedObject(self, &normalBackgroundColorKey);}- (void)setNormalBackgroundColor:(UIColor *)normalBackgroundColor {    objc_setAssociatedObject(self, &normalBackgroundColorKey, normalBackgroundColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}

However, the time to save the color is very important. At the very beginning, I chose to directly overwrite the color.setterMethod, stored before saving the colornormalColor.

- (void)setBackgroundColor:(UIColor *)backgroundColor {    self.normalBackgroundColor = backgroundColor;    _backgroundColor = backgroundColor;}

However, this seemingly operationalsetterIn fact, the view will not be colored.colorNormal colors do not respond, but the background color of the view is dark.

Because the above method does not work, I want to use the observer mode to storenormalColor, Register the instancecolorAttribute observer, whencolorWhen the property changes, notify the UIKit control and save the propertynormalColorAttribute.

However, when can I register myself as an Observer? I gave up this solution and finally chose a method to solve the problem.colorStorage problems.

The usage is adjusted to the original attributesetterAdd a hook to the method. Store the property before calling the method and use it to switch backnormalMode, assign a value to the attribute.

This issetterHook method for adjustment:

- (void)hook_setBackgroundColor:(UIColor*)backgroundColor {    if ([DKNightVersionManager currentThemeVersion] == DKThemeVersionNormal) {        [self setNormalBackgroundColor:backgroundColor];    }    [self hook_setBackgroundColor:backgroundColor];}

If the currentnormalMode, it will storecolorIf not, values will be assigned directly. If you don't understand why it seems to cause infinite recursion, please refer to it and explain in detail how the method adjustment is used.

DKNightVersionManager implementation colorSwitch

We have added the UIKit ControlnormalColorAndnightColorNext, we need to implementcolorSwitch between the two, andDKNightVersionManagerIt is the class for switching the processing mode.

PassDKNightVersionManagerCreate a singleton for processingMode Conversion,Use default color,Animation time.

WhenDKNightVersionManagerClass MethodnightFallingOrdawnComingFirst, we obtain the globalUIWindowAnd then recursively callchangeColorMethod to make the responsechangeColorChange the color of the method view.

- (void)changeColor:(id <DKNightVersionChangeColorProtocol>)object {    if ([object respondsToSelector:@selector(changeColor)]) {        [object changeColor];    }    if ([object respondsToSelector:@selector(subviews)]) {        if (![object subviews]) {            // Basic case, do nothing.            return;        } else {            for (id subview in [object subviews]) {                // recursice darken all the subviews of current view.                [self changeColor:subview];                if ([subview respondsToSelector:@selector(changeColor)]) {                    [subview changeColor];                }            }        }    }}

Because I have not introducedcategoryThe compiler does not knowidThe type has these two methods, so I declare a protocol to makechangeColorTo meet the requirements of the two methods.changeColorAndsubViews. Do not let the compiler prompt an error.

@protocol DKNightVersionChangeColorProtocol <NSObject>- (void)changeColor;- (NSArray *)subviews;@end

Then let all the UIKit controls follow this Protocol. Of course, we can also follow this protocol explicitly, as long as it can respond to these two methods.

Default color

We need to implement the default night color scheme in DKNightVersion to reduce developers' workload.

HowevercolorThis is only implemented once in the parent class, so that the subclass can inherit the implementation of the parent class, but also does not want the UIKit subclass to inherit the default color of the parent class.

- (UIColor *)defaultNightBackgroundColor {    BOOL notUIKitSubclass = [self isKindOfClass:[UIView class]] && ![NSStringFromClass(self.class) hasPrefix:@"UI"];     if ([self isMemberOfClass:[UIView class]] || notUIKitSubclass) {         return UIColorFromRGB(0x343434);    } else {        UIColor *resultColor = self.normalBackgroundColor ?: [UIColor clearColor];        return resultColor;    }}

UseisMemberOfClass:Method to Determine whether the instance is an instance of the current class, rather than an instance of this class subclass. then the default color is returned. however, non-UIKit subclasses can inherit this feature. Therefore, use this code to determine whether the instance is a non-UIKit subclass:

[self isKindOfClass:[UIView class]] && ![NSStringFromClass(self.class) hasPrefix:@"UI"]

We passNSStringFromClass(self.class) hasPrefix:@"UI"Cleverly achieve this purpose.

Use erbGenerate Objective-C code

Most of the work of this framework is repeated, but I don't want to write almost the same code for every class repeatedly. Such code is very difficult to read and maintain, so I usederbFile to provide a template for the generated Objective-C code, parse the metadata and pass in each template to dynamically generate all the code, add all the files to the directory using another script.

The implementation of DKNightVersion is not complicated.erbAnd Ruby scripts reduce a lot of work and useobjc/runtimeTo add the night mode for iOS apps.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.