如何为iphone应用程序创build多个主题/皮肤?

我有一个iPhone应用程序准备和应用程序商店批准。 现在我想为我的应用程序创build不同的主题。 有人可以帮助我,与信息/链接/步骤如何创build我的应用程序的主题?

我想创build一个男孩的金属主题和女孩粉红色的主题。 我的意思是,整个应用程序(function和function)将保持不变,但取决于用户是谁(男孩或女孩),他/她可以select他们希望看到的主题。 而当主题改变时,只有图像/背景/音乐会根据所应用的主题而改变。

非常感谢!

这是相当困难的应用程序没有相当于一个CSS样式表。

首先,你需要弄清楚你想要皮肤的哪些部分,以及什么时候允许用户交换皮肤。

我假设你想要改变图像和字体颜色,如果用户必须重新启动应用程序来改变皮肤(这会使事情变得更简单),那也没问题。

创build一个包含所有可换肤图像和颜色的plist。 plist将是一个带有明智的,主题中性的图像和颜色名称的字典(例如,没有称为“red”的颜色,称为“primaryHeadingColor”)。 图像将是文件名,颜色可以是hexstring,例如FF0000红色。

每个主题都有一个plist。

创build一个名为ThemeManager的新类,并通过添加以下方法使其成为单例:

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

ThemeManager类将有一个名为“styles”的NSDictionary属性,在init方法中,您将像下面这样将主题加载到样式字典中:

 - (id)init { if ((self = [super init])) { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSString *themeName = [defaults objectForKey:@"theme"] ?: @"default"; NSString *path = [[NSBundle mainBundle] pathForResource:themeName ofType:@"plist"]; self.styles = [NSDictionary dictionaryWithContentsOfFile:path]; } return self; } 

(注意:有些人不喜欢在init方法中做很多工作,我从来没有发现它是一个问题,但是如果你愿意的话,可以创build一个单独的方法来加载主题字典并从应用程序中调用它设置代码)。

请注意,我是如何从用户默认获取主题plist的名称的。 这意味着用户可以在首选项中select一个主题并保存,而应用程序将在下次启动时加载该主题。 如果没有select主题,我已经input了一个默认的主题名称,所以确保你有一个default.plist主题文件(或者将代码中的@“default”更改为默认主题plist实际调用的任何内容)。

现在你已经加载了你的主题,你需要使用它; 我假设你的应用程序有各种图像和文本标签。 如果你正在加载代码,那么这部分很容易。 如果你用笔尖做这个,那有点麻烦,但我会解释如何处理。

现在通常你会加载一个图像说:

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

但是如果你想让这个图像成为可能的话,你现在需要通过说明加载它

 NSDictionary *styles = [ThemeManager sharedManager].styles; NSString *imageName = [styles objectForKey:@"myImageKey"]; UIImage *image = [UIImage imageNamed:imageName]; 

这将在您的主题文件中寻找匹配键“myImageKey”的主题图像,并将加载它。 根据你已经加载的主题文件,你会得到不同的风格。

你会使用这三行很多,所以你可能想把它们包装在一个函数中。 一个好主意是在UIImage上创build一个类来声明一个类似这样的方法:

 + (UIImage *)themeImageNamed:(NSString *)key; 

然后使用它,你可以取代任何调用[UIImage imageNamed:@“foo.png”]; 与[UIImage themeImageNamed:@“foo”]; foo现在是主题键而不是实际的图像名称。

好吧,这是主题你的图像。 要为您的标签颜色设定主题,假设您目前正在设置标签颜色,请说出:

  someLabel.color = [UIColor redColor]; 

您现在将replace为:

 NSDictionary *styles = [ThemeManager sharedManager].styles; NSString *labelColor = [styles objectForKey:@"myLabelColor"]; someLabel.color = [UIColor colorWithHexString:labelColor]; 

现在你可能已经注意到UIColor没有方法“colorWithHexString:” – 你必须添加一个类别。 你可以谷歌的“UIColor与hexstring”的解决scheme,find代码来做到这一点,或者我已经写了一个方便的类别,这样做,更在这里: https : //github.com/nicklockwood/ColorUtils

如果你一直在关注,你也会想到,不要一遍又一遍地写这三行,为什么不给UIColor添加一个名为:

 + (UIColor *)themeColorNamed:(NSString *)key; 

就像我们用UIImage做的一样? 好想法!

就是这样了。 现在,您可以在应用中呈现任何图片或标签。 您可以使用相同的技巧来设置字体名称,或任何其他可能的可视化视觉属性。

只有一件我们已经忘记的小事

如果你已经把你的大部分视图构build成了笔尖(而且没有理由不这么做),那么这些技巧就不能工作,因为你的图像名称和字体颜色被埋在了难以理解的笔尖数据中,在您的源代码中设置。

有几种方法可以解决这个问题:

1)您可以制作副本的笔尖主题副本,然后将主题pipe理器中的笔尖名称放入您的主题pipe理器。 这不是太糟糕,只需要像这样实现视图控制器的nibName方法:

 - (NSString *)nibName { NSDictionary *styles = [ThemeManager sharedManager].styles; return [styles objectForKey:NSStringFromClass([self class])]; } 

注意我使用视图控制器的类名称作为键的巧妙技巧 – 这将节省您一些input,因为您可以使用该方法创build一个基本的ThemeViewController,并让所有可视化的视图控制器inheritance它。

这种方法确实意味着维护每个笔尖的多个副本,如果您以后需要更改任何屏幕,这是一个维护噩梦。

2)您可以为您的笔尖中的所有imageViews和标签制作IBOutlets,然后在您的viewDidLoad方法中将代码中的图像和颜色设置。 这可能是最麻烦的方法,但至less你没有重复的笔尖维护(这本质上是同样的问题,本地化笔尖顺便说一句,几乎相同的解决scheme选项)。

3)您可以创build一个名为ThemeLabel的UILabel的自定义子类,当实例化标签时,使用上面的代码自动设置字体颜色,然后通过将标签的类设置为ThemeLabel,在您的nib文件中使用这些ThemeLabels而不是常规UILabel。界面生成器。 不幸的是,如果你有不止一种字体或字体颜色,你需要为每种不同的风格创build一个不同的UILabel子类。

或者,您可能会迂回,并使用view标签或accessibilityLabel属性作为样式字典键,以便您可以拥有一个ThemeLabel类,并在Interface Builder中设置辅助function标签以select样式。

同样的技巧可以用于ImageViews – 创build一个名为ThemeImageView的UIImageView子类,在awakeFromNib方法中,将图像replace为基于标签或accessibilityLabel属性的主题图像。

就我个人而言,我最喜欢选项3,因为它节省了编码。 选项3的另一个优点是,如果你想在运行时交换主题,你可以实现一个机制,让你的主题pipe理器重新加载主题词典,然后向所有ThemeLabel和ThemeImageView广播一个NSNotification告诉他们自己重绘。 这大概只需要额外的15行代码。

无论如何,你有一个完整的iOS应用主题解决scheme。 别客气!

更新:

从iOS 5开始,现在可以在Interface Builder中通过keyPath设置自定义属性,这意味着不再需要为每个可设置属性创build视图子类,或者滥用标记或accessibilityLabel来select样式。 只要给你的UILabel或者UIImageView子类一个string属性来指明它应该从plist使用哪个主题键,然后在IB中设置这个值。

更新2:

从iOS 6开始,现在iOS内置了一个有限的皮肤系统,允许您使用一个名为UIAppearance的代理来同时皮肤给定控件类的所有实例(这里有一个关于UIAppearance API的好教程)。 这是值得检查这是否足够满足您的皮肤需求,但如果不是,我上面概述的解决scheme仍然运作良好,可以用来代替,或结合UIAppearance。