How to switch skins (or design themes) in iOS app? - iphone

I'd like to make my iPhone app to be able to switch between skins (or design theme, or look and feel, such as wooden, metal, earth color, men's, girls, etc...).
I'll prepare some sets of skins that contains images for buttons and backgrounds, sounds, and text color, and let the user decide which set of skin they want to use by the application settings.
What is the best practice to implement this?
The conditions are:
I'd like to use Interface Builder
I need to support iOS 3.1.3 and later
I want to make the sets of skins downloadable from the internet (I can't bundle all the skins in the app, as one set of skin requires lots of images and the app file size could become huge if I do so... I also don't want to hardcode any information about specific skins.)
If a custom skin does not contain one or some elements, (such as an image or sound file), I want it to use the missing element from the default set of skin.
I don't want to create Nib files for each skin. The Nib file for one screen should be the only one in the main bundle for easier maintenance.
I'm thinking about making a superclass of all the UIViewControllers in my app and override the part that it loads Nib file, and instead of loading from the main bundle, load the resources from the skin that is saved in the Document directory... but I don't know how to do it... The default behavior of the Nib-loading methods always loads resources from the main bundle and the information about resource file names are lost after reading... :(
Thanks in advance for your help.

Am not sure about best practice .. But, if your app is not big enough, then a well structured plist is your friend.
Initially, you could choose: Metal Theme. The following should hold:
You either have a Singleton ThemeManager, or just stick an NSDictionary to one of your Singletons if appropriate.
The point behind the ThemeManager is the mapping between the asset and the theme..
Some sample code (written directly on SOF .. Don't mind Syntax mistakes):
#define kThemeMap(__x__) [[ThemeManager sharedManager] assetForCurrentTheme:__x__]
...
-(void)doUselessStuff {
UIImage* backgroundImage = [UIImage imageNamed:kThemeMap(#"FirstViewBG")];
...
}
//in the ThemeManager:
//returns the appropriate name of the asset based on current theme
-(NSString*)assetForCurrentTheme:(NSString*)asset {
//_currentTheme is an NSDictionary initialized from a plist. Plist can be downloaded, too.
NSString* newAsset = [_currentTheme objectForKey:asset];
if(newAsset == nil) {
newAsset = [_defaultTheme objectForKey:asset];
}
return asset;
}
//Let us assume the user selects Metal Theme somewhere .. Still coding ThemeManager:
-(void)selectedNewTheme:(NSString*)newTheme {
//First, get the full path of the resource .. Either The main bundle, or documents directory or elsewhere..
NSString* fullPath = ...;
self.currentTheme = [NSDictionary dictionaryWithContentsOfFile:fullPath];
}
The plist files are just a dictionary with string to string mapping... something like this:
//Default.plist
#"FirstViewBG" : #"FirstViewBG_Default.png"
#"SecondViewBG" : #"SecondViewBG_Default.png"
#"WinSound" : #"WinSound_Default.aiff"
//Metal.plist
#"FirstViewBG" : #"FirstViewBG_Metal.png"
#"SecondViewBG" : #"SecondViewBG_Metal.png"
#"WinSound" : #"WinSound_Metal.aiff"
Alternatively, you can just save the postfix, if that is good enough for you.. But, it will require string manipulation, by slicing the extension -> adding the postfix -> adding the extension ..
Or maybe make it a prefix?

You can category on UIImage with the methored imageNamed:, use the custom imageNamed: instead of the default one.
In the custom methord, selected the image by theme.

Related

How to identify that asset added inside Assets.xcassets are used in project?

How to identify quick way the Assets added inside Assets.xcassets for Images & color are using inside project or not.
Example:
int value = 10
In this case int value not used inside application which give an warning.
Initialization of immutable value 'value' was never used; consider replacing with assignment to '_' or removing it
What if inside Assets.xcassets added color or image are not used how to identify ?
Xcode has no tool which could highlight not used assets but there is a open source project called "AssetsChecker" which will do the job.
There's no way a tool can know which assets are not being used by your application.
Imagine that you are creating a Weather app, and the data you receive from the server includes the image_key that you use to know which asset to load.
If a tool to find unused assets was used, it would tell you that every image or color that is not referenced directly is not used, which would yield a LOT of false positives.

Dynamic font change and font color changes in Iphone application

I have an application which get the settings values such as font color style etc from API.
The user can edit those values from web view and those need to be reflected in the APP.
Can any one suggest the best method to integrate with the app.??
My suggestion:
Use a convenient JSON framework, such as stig's JSON-Framework.
Get the info from the server in JSON format (obviously), via NSURLConnection (documentation here).
Assign the properties of your UI elements such as textColor, font etc.
Seems doable - but based on the given information I would perhaps recommend to let your users do that from within the app. It would be much more intuitive.
EDIT: More specific implementation info.
You can simply use global variables. E.g., make a class Formats which stores all the values you need, fetching and parsing them as necessary (lazily). Then, when you need certain formatting, just use code like
Formats *format = [[[Formats alloc] init] autorelease]; // or pass a reference
myNameTextField.textColor = [format textColorForNames];

How to react to failed thumb image loading in TTThumbsViewController?

I'm currently using TTThumbsViewController in my project. I'm getting all the urls for TTPhotoVersionLarge and TTPhotoVersionThumbnail from the web so I can't tell that a url for the thumb images will work or not.
Currently the TTThumbsViewController will just display an empty image if the thumb url can't be loaded.
So I want to be notified if a thumb fails to load and do extra error handling when that happens like:
Try to load the url for TTPhotoVersionLarge
If that fails again display an error image (which is included in the bundle)
I have looked into the three20 code but can't find a proper place where I can implement this proper error handling.
The Three20 library is great, but I've found that it's often hard to change parts of their library such as this. For instance, TTThumbsViewController basically only allows you to set the dataSource and then takes care of the rest. If you want more control, perhaps look into code such as AQGridView: http://quatermain.tumblr.com/post/528737778/aqgridview-lives-for-my-ipad-dev-camp-hackathon
I've chosen to use that over Three20's equivalent because it gives you more control over what happens with your data.
Edit: In response to using TTThumbsViewController heavily, you may want to look at this method in TTTHumbsViewController.m:
- (NSString*)URLForPhoto:(id<TTPhoto>)photo {
if ([photo respondsToSelector:#selector(URLValueWithName:)]) {
return [photo URLValueWithName:#"TTPhotoViewController"];
} else {
return nil;
}
}
It looks like you should be able to specify a different value there so long as you can find something to add to the if statement determining if the initial loading failed from the dataSource.

One App, Multiple Branding

I have made an application for the iPhone but it is required to be released with multiple brandings. Eg Differernt:
App Name
Icons
Default.png
Text replaced for the app name in IB
Colour schemes for all images such as backgrounds, icons etc
I'm not sure of the best way to do this.
I was thinking of a plist file for each branding that would have the name of the files to load eg "brand1_background.png" for brand1 but that would get very messy with the text replacement. It would also mean that all brands images would be in the package making it of larger size.
Looking around a bit I could have an 'images' folder for each brand and drag it in to build that brand's app, however the text is still an issue.
I'm wondering how everyone else would handle this situation as I want to do it as right as possible.
There are 2 different aspects to this problem, which I'd describe as follows:
Stuff that can be changed dynamically
Stuff that can't be changed dynamically
The first category is super easy. If you have your colo(u)r schemes stored in some easily-readable format like a plist or whatever, you can just load up that file during app startup, and build UIColor objects from them and use those where appropriate. The same goes for images used within the app itself. This is not a hard problem.
The second category is trickier. This is stuff that has to be baked into the application because of code signing. This means that the things like the App Name, the icon, Default.png, etc, all have to be changed before the app is signed in the compilation process. So what I'd do is bake up a bunch of scripts to take your branding information (name, image files, icons, etc) and load it up, then generate your Info.plist file and whatnot. This should be done as one of the first phases of your compilation.
For what it's worth, I work on an application where we do exactly this process, and it works pretty well. It's a bit tedious to update when we change what resources get branded, but I'm not sure there's any decent way around that.
Create a target for each of your brandings. For each single target you can add different files (e.g. images) and set an app name. You can even use the same file names (but stored under a different location) and you can build your brand-apps pretty fast.

iPhone Localization: simple project not working

Im doing my first localized project and I've been fighting with it for several hours with no luck.
I have to create an app that, based on the user selection, shows texts and images in different languages.
I've read most of Apple's documents on the matter but I cant make a simple example work.
This are my steps so far:
1) Create a new project.
2) Manually create a "en.lproj" directory in the projects folder.
3) Using TexEdit create file called "Localizable.strings" and store it in Unicode UTF-16. The file looks like this:
/*
Localizable.strings
Multilanguage02
Created by Gonzalo Floria on 5/6/10.
Copyright 2010 __MyCompanyName__. All rights reserved.
*/
"Hello" = "Hi";
"Goodbye" = "Bye";
4) I drag this file to the Resources Folder on XCode and it appear with the "subdir" "en" underneath it (with the dropdown triangle to the left). If I try to see it on XCode it looks all wrong, whit lots of ? symbols, but Im guessing thats because its a UTF-16 file. Right?
5) Now on my view did load I can access this strings like this:
NSString *translated;
translated = NSLocalizedString(#"Hello", #"User greetings");
NSLog(#"Translated text is %#",translated);
My problem is allowing the user to switch language. I have create an es.lproj with the Localizable.strings file (in Spanish), but I CANT access it.
I've tried this line:
[[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObjects:#"es", nil] forKey:#"AppleLanguages"];
But that only works the NEXT time you load the application. Is there no way to allow the user to switch languages while running the application??
Do I have to implement my own Dictionary files and forget all about NSLocalizableString family?
Thanks for ANY advice or pointers.
Gonso
There is already a discussion about that here.
Their suggestion is to create a sub-bundle and then use a method called NSLocalizedStringFromTableInBundle(...) (as described in the reference manual) to
get a localized string from a specific table in a bundle.
I am just giving you an hunch, I haven't tried but, I guess, this could be a good way to face your problem.