Dknightversion implementation---How to add night mode to IOS apps

Source: Internet
Author: User
Tags uikit

In many of the software that reads or needs to be watched at night, the nightly pattern is a feature that the APP needs. And how to add the night mode gracefully to the application without changing the original architecture or even changing the original code is an issue that has to be faced in many application development processes.

It is the driving of these things that makes me think about how to use an elegant and concise way to solve this problem.

And Dknightversion is the solution I bring.

So far, most of the work on this framework has been done, and perhaps it is not perfect now, but I will continue to maintain this framework to help engineers who are suffering from night-time patterns to solve this hole's demand.

Realize

Now I finally have time to water a water to write a blog about how this framework implements night mode, and what features it has.

For a long time I was wondering how to UIKit add Night mode to the IOS App without having to override the controls. and objc/runtime I have the hope that I UIKit can achieve this goal without the written words.

Adding a UIKit control nightColorProperty

Because we do not CBD the UIKit control, and then use the @property Add property for its subclasses. Instead, use the Magic category in Objective-c and objc/runtime add properties to the controls for the UI family.

Use objc/runtime to add attributes to a category it is believed that many people know and are often used in development. If you don't know, you can look here.

Dknightversion for most commonly used color , say: backgroundColor tintColor all added to the night beginning of the night mode in the color nightBackgroundColor nightTintColor .

-(Uicolor*) Nightbackgroundcolor{ReturnObjc_getassociatedobject(Self,&nightbackgroundcolorkey)?:Self. backgroundcolor);}- (void) Setnightbackgroundcolor : (Uicolor *{ Objc_setassociatedobject (self&nightbackgroundcolorkey ;}   

We create this property to save the color in the night mode so that when the theme of the app is switched to night mode, the nightColor property stores the color assigned to the corresponding color , but there is a problem. When the app is re-switched back to normal mode, we lose the original normal mode color .

Add to normalColorStore color

To solve this problem, we added another property for the UIKit control normalColor to hold the color in normal mode.

-(Uicolor*) Normalbackgroundcolor{ReturnObjc_getassociatedobject(Self,&normalbackgroundcolorkey);}- (void) Setnormalbackgroundcolor : (Uicolor *{ Objc_setassociatedobject (self&normalbackgroundcolorkey ;}   

But the time to save this color is very important, at the very beginning, my choice is to overwrite the   setter method, save the   before saving the color; normalcolor .

-void" Setbackgroundcolor: (UIColor *) backgroundcolor { self.normalbackgroundcolor = backgroundcolor = Backgroundcolor;}      

However, this seemingly operational results in the setter view will not be colored, the settings color including normal color will not have any reaction, but the background color of the view is dark.

Since this method does not work, I would like to use the Observer pattern to store normalColor , register the instance itself as an color observer of the property, when the color property changes, notify the UIKit control itself, and then save the property to the normalColor property.

But the question of when to register myself as an observer has made me abandon this solution. Finally, the method is chosen to solve color the original storage problem.

Use the method to add hooks to the original property, setter store the property before the method call, and normal assign a value to the property when switching back to mode.

This is the setter hook method to be used with the dispensing:

-(void) Hook_setbackgroundcolor:(Uicolor*) BackgroundColor{if  ( Span class= "token punctuation" >[dknightversionmanager currentthemeversion == dkthemeversionnormal) { [self setnormalbackgroundcolor:backgroundcolor] [self Hook_setbackgroundcolor:backgroundcolor]             /span>       

If the current normal mode, it will be stored color , if not it will be directly assigned, if you do not understand why this seems to cause infinite recursion, see here, detailed explanation of how the method is used.

Dknightversionmanager implementation colorSwitch

We have added and for the UIKit normalColor control nightColor , and then we need to implement the color switch between the two, and this DKNightVersionManager is the class to handle the mode switch.

By DKNightVersionManager creating a singleton to process, and 模式转换 使用默认颜色 动画时间 so on.

When invoking DKNightVersionManager a class method nightFalling or dawnComing , we first get the global UIWindow , and then recursively call the method to changeColor changeColor change the color of the view that responds to the method.

-(void) ChangeColor:(ID<dknightversionchangecolorprotocol>) object{If([Object Respondstoselector:@selector(ChangeColor)]){[Object ChangeColor];}If([Object Respondstoselector:@selector(Subviews)]){If(![Object Subviews]){Basic case, does nothing.Return;}Else{For(ID SubviewInch[Object Subviews]){Recursice Darken all the subviews's current view.[Self ChangeColor:subview] span class= "token keyword keyword-if" >if  ([subview Respondstoselector: @selector Span class= "token punctuation" > (Changecolor]< Span class= "token punctuation") {[subview Changecolor]; } } } }         

Because I did not introduce   in this class; category , compiler does not know   ID   type has both methods. So I declare a protocol that makes   ChangeColor   methods to satisfy the two methods   ChangeColor   and   subviews . Do not let the compiler prompt for errors.

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

Then let all the UIKit control follow this protocol, and of course we can not explicitly follow this protocol, as long as it can respond to both methods is also possible.

Implement default Colors

We want to implement the default night-mode color matching in dknightversion to reduce the developer's workload.

But because we color implement each one only once in the parent class, this allows subclasses to inherit the implementation of the parent class, but also does not want the UIKit class 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){Returnuicolorfromrgb ( else { Uicolor *resultcolor = self.normalbackgroundcolor ?[uicolor clearcolor]< Span class= "token punctuation"; return resultcolor}}           

by using   Ismemberofclass:   method to determine that the instance is not an instance of the current class, not an instance of the class subclass .  then returns the default color. but not UIKit. Can inherit this attribute, so use this code to determine if the instance is a subclass of UIKit:

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

We have NSStringFromClass(self.class) hasPrefix:@"UI" achieved this through ingenious means.

Use erbGenerate OBJECTIVE-C Code

Most of the work in this framework is repetitive, but I don't want to write nearly the same code for each class, which is very difficult to read and maintain, so I used a erb file to provide a template for the generated objective-c code, parse the metadata and pass in every template, Generate all the code dynamically, and then add all the files to the directory through another script.

The implementation of dknightversion is not complicated. Not only did it use the erb Ruby script to reduce the amount of work, but also used objc/runtime the feature to change the UIKit component to the effect of adding night mode to IOS apps.

Dknightversion implementation---How to add night mode to IOS apps

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.