0

I have recently released my first app to the App Store and still have a very long way to go with iOS development.

I'm looking to introduce themes into my app as an update so the user can select from 4-5 different themes.

I've got a tab bar controller and have set the 5th tab to be the "Settings" tab which contains a Table View with cells. The first cell contains the text "Themes" where the user can select it, be taken to a new Table view/Collection View to select the themes.

So I searched online and came across this incredible answer on doing just this:

How to create Multiple Themes/Skins for iphone apps?

Because I'm still new to development, I'm in need of assistance to take this forward.

To start off with, I have two themes:

1) DefaultTheme (Newiphonebackground.png)

2) PurplePinkTheme (Purplepinknew.png)

Following the instructions, I have created one plist for the Default theme and one plist for the PurplePink theme.

In the ThemeManager class that I created, I have:

- (id)init
{
    if ((self = [super init]))
    {
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
        NSString *themeName = [defaults objectForKey:@"theme"] ?: @"DefaultTheme";

        NSString *path = [[NSBundle mainBundle] pathForResource:themeName ofType:@"plist"];
        self.styles = [NSDictionary dictionaryWithContentsOfFile:path];
    }
    return self;
}

+ (ThemeManager *)sharedManager
{
    static ThemeManager *sharedManager = nil;
    if (sharedManager == nil)
    {
        sharedManager = [[ThemeManager alloc] init];
    }
    return sharedManager;
}

In my table view, where the theme will get applied (it's going to get applied to every screen in the app but this is just to start off with where I'm testing with one scene in the app), in the viewDidLoad, I put:

    NSDictionary *styles = [ThemeManager sharedManager].styles;
    NSString *imageName = [styles objectForKey:@"DefaultTheme"];
    UIImageView *backgroundImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:imageName]];
    self.tableView.backgroundView = backgroundImageView;

That does nothing different because it applies the default theme. However if in the ThemeManager, I change the plist to be:

    NSString *themeName = [defaults objectForKey:@"theme"] ?: @"PurplePinkTheme";

and in the viewDidLoad of the separate Table View, I set the code to be:

    NSString *imageName = [styles objectForKey:@"PurplePinkTheme"];

Then upon loading my application, my PurplePinkTheme loads.

So far so good, but I don't think I've done anything substantial here.

I am confused from this point on. I am looking to start off with changing just the background images from the in-app settings and once I have that done, I'll look to change the custom navigation bars, etc.

So my questions are:

1) Why do I create one plist per theme?

2) How exactly do I link multiple plists in the ThemeManager class?

3) How do I link all of the themes up to the settings Theme cells allowing the user to choose?

I'm sorry this is vague, but I really need to understand how exactly I can carry on here. For example, I just don't get how to have multiple plists in the ThemeManager and how to move forward from here.

To recap, I, for now just want the ability to have multiple plist files with the different backgrounds, and for the user to go the settings tab in my app, click on the "Themes" cell and be able to select a different theme for the app without restarting the app.

I know the tutorial does carry on with explanations on that, but I'm just not quite sure I understand it all.

Any guidance on this would be massively appreciated.

Many thanks,

Community
  • 1
  • 1
amitsbajaj
  • 1,304
  • 1
  • 24
  • 59

1 Answers1

1

Your question is super long so I must confess I did not read the whole thing. That said I spent a lot of time with themes and the best solution I have found is to create an object that handles formatting. This is how I think you can implement it:

  1. Create a formatter object extending NSObject
  2. Have a property for each changeable piece of the theme:

    for example if the background changes images you can have a UIImage in there called background. If the font color changes you have a UIFont property in there.

  3. create a shared instance of your formater by adding:

     +(Formater *) sharedInstance; //add to .h
    
    
    + (Formater *) sharedInstance //add to .m
    {
        if (!_sharedInstance)
        {
            _sharedInstance = [[Formater alloc] init];
        }
    }
    
  4. Now in your view controller all you need to do is create a reference to your shared item and use that to style your view controller. (remember to make the changes in viewWillAppear not or it will not change after the setting is changed.

Voila!

Mika
  • 5,807
  • 6
  • 38
  • 83
  • Dear @Mikael - many thanks for the reply and apologies the question was long; I wanted to provide as much information as possible. Your solution looks to be incredible to make this happen. I just need to clarify a few minor things: in the view controller, I create a reference to the SharedInstance - how would I set the background? For example, if the user clicks the 2nd cell, how would I specifically "set" the theme in the viewWillAppear? Also, how do I get this to theme the entire app? (There are about 11 different scenes that will need to be themed with the selected theme) Many thanks – amitsbajaj Mar 17 '14 at 11:43
  • Essentially, what I mean by the previous comment is: how can I get the user's selection of theme to theme the entire app? So if the user goes to the settings of the app, clicks themes, selects "Dark", how do I suddenly get the entire app to theme with that, with every single scene? – amitsbajaj Mar 17 '14 at 11:46
  • In each view controller you do: `Formater *formater = [Formater sharedInstance];` Then you can do: `[self.view.backgroundColor = formater.backgroundColor];` in the view controller. – Mika Mar 17 '14 at 13:47
  • Thanks Mikael - that makes sense. What I'm confused about is how to "capture" which theme the user has selected from the Settings Table View. So the user goes to the Settings, selects a "theme" from the Table View, I know how to capture the selected row with didSelectRow, but how would I pass that to other table views to then put your Formatter sharedInstance code in? Would I for example use a delegate? – amitsbajaj Mar 17 '14 at 14:15
  • You can make that a property of Formater as well. Where you store it depends on how your application is structured. Option 1: You save it on your server and pass it to the app on login. Option 2: You set it on the app and store it in NSUserDefaults. – Mika Mar 17 '14 at 15:20
  • Thanks Mikael - that's really helpful. Sorry, just back to the comment earlier. I'm trying to change the backgroundImage, so I have a property UIImage on the Formatter class.. in the viewWillAppear, I call Formatter sharedInstance, etc.. and your next line, but where do I "set" the actual image? – amitsbajaj Mar 17 '14 at 16:18
  • You set it exactly like any other image but instead of writing `= [UIImage imageWithName:....]` you can simply point to the image in the formater class. If you do not know how to set the background image of a UIViewController you can look here: http://stackoverflow.com/questions/2991040/uiviewcontroller-with-background-image – Mika Mar 17 '14 at 16:35
  • Thanks Mikael - that makes sense. I'm sorry for so many questions, but how would I set my formatter where background can be a choice of 4 images. If i call formatter.background in each view controller, I just don't understand how I'd select the image based on formatter.background, unless there's some way I can set that in the Formatter class, or something? – amitsbajaj Mar 17 '14 at 17:24
  • Depending on what theme is selected you set formater.backgroundImage. So if theme 1 is selected you set backgroundImage to image 1. If theme 2 is selected you set backgroundImage to image 2. – Mika Mar 17 '14 at 17:48
  • Thanks @Mikael. That's really helpful. Your answer is brilliant and I just need to ask you another question. How can I set a custom background for the UITabBar using the same techniques? What I'm finding is that in the viewWillAppear, if I set the UITabBar background image, it never changes throughout the app. Do you have any experience with how to theme a UITabBar/ – amitsbajaj Mar 19 '14 at 08:01