iOS development-Using technology OC Tablets & Skin Care (day and night)

Source: Internet
Author: User
Tags uikit

Skin changing (day and night)

One: The first is to use a simple method to achieve

Do not remember who said, China's users are probably the world's most like a multi-skin features of users. I hate to write Android programs, graphical interface design tools and difficult to use, not as good as handwriting, editor slow like snail, smart tips always keep up with the speed I entered, the same function, Android code is at least three times times the iOS, each line of code, feel their fingers in the blood. But Android's flexible and unified style function is really intimate! Before 5, there was no better way to achieve the same functionality on the iOS platform.

Apple binds all the interface components to a protocol called Uiappearance, and you can simply set the overall style of the component through uiappearance.

  For example, I want to set all the UIButton title to white:
[[UIButton appearance] Settitlecolor:[uicolor Whitecolor] forstate:uicontrolstatenormal];
Or, I think all the UIButton have a uniform background image.
[[UIButton appearance] Setbackgroundimage:abackgroundimage Forstate:uicontrolstatenormal];
Of course, the actual project, the different style of the component, should be defined as a separate class, and then in its Initialize method set its uiappearance, for example, I define a Afkbutton class, I can write the following, The button for all Afkbutton classes in this application is a style.
1 @implementationAfkbutton2   ......3+ (void) Initialize {4      if(Self = =[Afkbutton Self]) {5 [[Self appearance] Settitlecolor:[uicolor Whitecolor] forstate:uicontrolstatenormal];6 [self appearance] setbackgroundimage:abackgroundimage forstate:uicontrolstatenormal];7      }8  }9 ......Ten @end
To modify the uiappearance, there is a limitation, that is, if you want it to take effect, it must be loaded into the app's main window the next time, so if you want to dynamically modify the style of the component through uiappearance, we need to implement the following code in Uiappdelegate
1 uiviewcontroller *rootviewcontroller = Self.window.rootViewController; 2  Self.window.rootViewController = Nil; 3  4  5[[UIButton appearance] Setbackgroundimage:abackgroundimage Forstate:uicontrolstatenormal] ; 6   7  Self.window.rootViewController = Rootviewcontroller;
As described above, I designed the style of the dynamic switch skin as follows:
    • 1. First build the corresponding component class according to style, for example, you have several buttons, you can implement several button classes on inheritance.
    • 2. Set the global style flag.
    • 3. Trigger the style modification where the message is sent through the global broadcast.
    • 4.UIAppDelegate Reload Window's Rootviewcontroller
Second: Use of third-party

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

The pit of a forced

Demand.

Realize

And now I finally have time to

Water One Water

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 .

1 -(Uicolor *) nightbackgroundcolor {2   return objc_getassociatedobject (self , &nightbackgroundcolorkey)? : Self.backgroundcolor); 3 }4 -(void) Setnightbackgroundcolor: (Uicolor *) nightbackgroundcolor {5    objc_setassociatedobject (self, &Nightbackgroundcolorkey, Nightbackgroundcolor, objc_ association_retain_nonatomic); 6 }

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.

1 -(Uicolor *) normalbackgroundcolor {2   return objc_getassociatedobject ( Self, &normalbackgroundcolorkey); 3 }4 -(void) Setnormalbackgroundcolor: (Uicolor *) normalbackgroundcolor {5    objc_setassociatedobject (self, &Normalbackgroundcolorkey, Normalbackgroundcolor, objc_ association_retain_nonatomic); 6 }

But the time to save this color is very important, and at the very beginning, my choice is to overwrite the setter method directly before storing the color normalColor .

-(void) SetBackgroundColor: (Uicolor *) backgroundcolor {    = 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:

1 -(void) Hook_setbackgroundcolor: (uicolor*) backgroundcolor {2     if ([dknightversionmanager currentthemeversion] = = dkthemeversionnormal) {3        [self Setnormalbackgroundcolor:backgroundcolor]; 4     }5    [self hook_setbackgroundcolor:backgroundcolor]; 6 }

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.

1- (void) ChangeColor: (ID<DKNightVersionChangeColorProtocol>)Object {2   if([Objectrespondstoselector: @selector (changecolor)]) {3[ObjectChangeColor];4   }5   if([Objectrespondstoselector: @selector (subviews)]) {6     if(! [ObjectSubviews]) {7       //Basic case, does nothing.8       return;9}Else {Ten        for(IDSubviewinch[ObjectSubviews]) { One         //Recursice Darken all the subviews's current view. A [self changecolor:subview]; -         if([Subview respondstoselector: @selector (ChangeColor)]) { - [Subview ChangeColor]; the         } -       } -     } -   } +}

Because I did not introduce it in this class category , the compiler does not know id that the type has both methods. So I declare a protocol that enables the changeColor methods in the method to satisfy both 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 controls follow this protocol, and of course we can also not show that following 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:[uiviewclass]] &&! [Nsstringfromclass (self.class) Hasprefix:@"UI"]; if([Self Ismemberofclass:[uiviewclass]] ||Notuikitsubclass) {     returnUicolorfromrgb (0x343434); } Else{Uicolor*resultcolor = Self.normalbackgroundcolor?: [Uicolor Clearcolor]; returnResultcolor; }}

Use the isMemberOfClass: method to determine if the instance is an instance of the current class, not an instance of the class subclass. The default color is then returned. But subclasses of non-UIKit can inherit this attribute, so use this code to determine if the instance is a subclass of non-UIKit:

class]] &&! [Nsstringfromclass (self.  Class) Hasprefix:@ "UI"]

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

Using erb generate OBJECTIVE-C code

Most of the work in this framework is repetitive, but I don't want to write almost 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, only parse the original data and pass in each 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. It not only uses the erband Ruby scripts reduce a lot of work and use objc/runtimeFeatures to change the UIKit component to the effect of adding night mode to IOS apps.

iOS development-Using technology OC Tablets & Skin Care (day and night)

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.