Theme skin for iOS development

Source: Internet
Author: User
Tags notification center

Recently, I was developing a public transport application. There is a module that involves topic settings. This article mainly talks about my practices.

The procedure is as follows:

(1): the entire application depends on a topic manager. The topic manager loads topics in different topic folders based on the current topic configuration.

(2): In each controller of the application, the topic image or color needs to be changed from the hard encoding method to the topic manager. (You can see that, although. XIB configuration UI is more efficient than coding rendering UI, but it is still somewhat less flexible and collaborative development)

(3): In the topic settings controller, once a topic is switched, a message needs to be sent like a system notification center (the purpose of this step is, it is mainly used to modify the theme of objects that already exist and the UI has been built)

Final View:

Https://github.com/yanghua/iBus#version-102preview

First, let's take a look at the directory structure of the topic Folder:

As you can see, the topic is usually prepared in advance. Of course, I don't have a backend server. If your application has a backend server, it can be more powerful, for example, the topic file is not stored in the bundle, but in the document of the sandbox application. In this way, when the application is started, you can check whether the server has a new topic package. If so, download the package and release it to the document, which is much more convenient, you do not need to use the new theme after the upgrade. The folder is blue rather than yellow. It is not the group of the xcode project, they are actually stored folders (they are also part of the app bundle, but they are obtained in a different way. The purpose is to facilitate the organization of files and directory structures of various themes ).

See how to get the topic folder path:

#define Bundle_Of_ThemeResource                                @"ThemeResource"//the path in the bundle#define Bundle_Path_Of_ThemeResource                                        \[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:Bundle_Of_ThemeResource]

Thememanager:

@interface ThemeManager : NSObject@property (nonatomic,copy) NSString                 *themeName;@property (nonatomic,copy) NSString                 *themePath;@property (nonatomic,retain) UIColor                *themeColor;+ (ThemeManager*)sharedInstance;- (NSString *)changeTheme:(NSString*)themeName;- (UIImage*)themedImageWithName:(NSString*)imgName;@end

We can see that themanager has three attributes and two instance methods open to the outside, and themanager is constructed as a singleton (single). During instance initialization, themanager also instantiates the configuration of the topic:

- (id)init{    if (self=[super init]) {        [self initCurrentTheme];    }        return self;}

Initcurrenttheme definition:

-(Void) initcurrenttheme {self. themename = [configitemdao get: @ "topic Settings"]; nsstring * themecolorstr = [configitemdao get: Self. themename]; self. themecolor = [uicolor parsecolorfromstr: themecolorstr]; self. themepath = [bundle_path_of_themeresource stringbyappendingpathcomponent: Self. themename]; // init UI uiimage * navbarbackgroundimg = [[Self encoding: @ "themecolor.png"] encoding: uiedgeinsetsmake (0.0f, 0.0f, 1.0f, 1.0f) resizingmode: callback]; [[uinavigationbar appearance] setbackgroundimage: navbarbackgroundimg forbarmetrics: uibarmetricsdefault];}

Here, we obtain the topic type and color from SQLite, configure the topic attributes, and initialize the consistent uinavigationbar. In other controllers, the image retrieval method is no longer:

UIImage *img=[UIImage imageNamed:@"img.png"];

Replaced:

UIImage *img=[[ThemeManager sharedInstance] themedImageWithName@"img.png"];

To ensure that img.pngis the img.png folder under the current topic File

The implementation is as follows:
- (UIImage*)themedImageWithName:(NSString*)imgName{    if (!imgName || [imgName isEqualToString:@""]) {        return nil;    }        NSString *imgPath=[self.themePath stringByAppendingPathComponent:imgName];        return [UIImage imageWithContentsOfFile:imgPath];}

On the topic settings page, select a new topic and call the changetheme method:

-(Nsstring *) changetheme :( nsstring *) themename {If (! Themename | [themename isw.tostring: @ ""]) {return nil;} nsstring * themepath = [inclustringbyappendingpathcomponent: themename]; If (direxistsatpath (themepath) {self. themepath = themepath; // update to DB [configitemdao set: [nsmutabledictionary dictionarywithobjects: @ [@ "topic Settings", themename] forkeys: @ [@ "itemkey ", @ "itemvalue"]; // init again [self initcurrenttheme];} return themename ;}

This is a simple thememanager. More configurations may be available, such as themedfontwithname :( nsstring *) fontname. Of course, the methods are the same. The above are just definitions to see how it works and how it works with the Controller. Basecontroller: Note: basecontroller is the super class of all other controllers. You can write an application or an app at any time, in the beginning, you should always plan the type inheritance relationship. This is very important. In my personal experience, I will always build a super class immediately after creating an application, this saves you a lot of trouble. I spoke nonsense again and entered the topic. In basecontroller, we open a public method:

- (void)configUIAppearance{    NSLog(@"base config ui ");}

This class is not implemented by default and is mainly used for sub class to override. For example, the implementation of a sub-controller is as follows:

- (void)configUIAppearance{    self.appNameLbl.strokeColor=[[ThemeManager sharedInstance] themeColor];    [self.commentBtn setBackgroundImage:[[ThemeManager sharedInstance] themedImageWithName:@"aboutBtnBG.png"]                               forState:UIControlStateNormal];        [self.shareBtn setBackgroundImage:[[ThemeManager sharedInstance] themedImageWithName:@"aboutBtnBG.png"]                             forState:UIControlStateNormal];        [self.developerBtn setBackgroundImage:[[ThemeManager sharedInstance] themedImageWithName:@"aboutBtnBG.png"] forState:UIControlStateNormal];        [super configUIAppearance];}

We can see that all the settings of the UI control that needs to use the topic are extracted and placed in configuiappearance.
This method is not explicitly called in all sub-controllers, because it is called in the viewdidload method of basecontroller. In this way, if the subclass override has it, it will call the subclass. If there is no override, it will call the default Implementation of basecontroller. As you can see, some UI appearances are configured in the above method, which will be called when a view show is displayed, and a call point is of course a theme change! When the topic changes, the Controller of all applications is in two states: (1) Not instantiated (2) has been instantiated, And the view has been built and is visible to the first State, we don't need to worry too much, because the changetheme method of themanager will be called when we select a new topic. This method will update the topic configuration of the database and init and config the new topic, so when the uninstantiated controller is instantiated later, it will certainly apply a new topic. However, it is not the first case for visible themes. Unless you show them again, new themes will not be applied automatically, however, it is impossible to re-build all other controllers after distory. Therefore, IOS notification is applied here, and the benefits of a basecontroller are displayed again, because we do not need to register message notifications for every existing controller and implement the method to process received notifications, what we do in basecontroller is done in all sub controllers that inherit it, isn't it? First, register the notification_for_themechanged notification that we are interested in basecontroller like the notification center: (call this registration method in the viewdidload of basecontroller)

- (void)registerThemeChangedNotification{    [Default_Notification_Center addObserver:self                                    selector:@selector(handleThemeChangedNotification:)                                        name:Notification_For_ThemeChanged                                      object:nil];}

The message processing logic is also provided:

-(Void) Configure :( nsnotification *) Notification {uiimage * navbarbackgroundimg = [[thememanager sharedinstance] region: @ "themecolor.png"] region: resize (0.0f, 0.0f, 1.0f, 1.0f) resizingmode: uiimageresizingmodetile]; [self. navigationcontroller. navigationbar setbackgroundimage: navbarbackgroundimg forbarmetrics: uibarmetricsdefault];
    [self configUIAppearance];

}
We can see that configuiappearance is called again here. Due to the inheritance relationship, the self pointer here is not directed to the basecontroller instance (but the sub controller instance), so the sub Controller method is also called. Therefore, although the "theme setting interface" may remain, other surviving controllers have received the notification for switching the topic and quietly completed the switchover. Finally, let's take a look at the general logic of topic switching:

- (void)themeButton_touchUpIndise:(id)sender{    //unselect    UIButton *lastSelectedBtn=(UIButton*)[self.view viewWithTag:(Tag_Start_Index  + self.currentSelectedIndex)];    lastSelectedBtn.selected=NO;        //select    UIButton *selectedBtn=(UIButton*)sender;    self.currentSelectedIndex=selectedBtn.tag - Tag_Start_Index;    selectedBtn.selected=YES;        [[ThemeManager sharedInstance] changeTheme:((NSDictionary*)self.themeArr[self.currentSelectedIndex]).allKeys[0]];        //post themechanged notification    [Default_Notification_Center postNotificationName:Notification_For_ThemeChanged                                               object:nil];}

The general process is like this ~ If you think the code snippets are too fragmented, it doesn't matter. All the implementation code is put on GitHub. And the entire application isOpen SourceOf!

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.