我已经准备好了一个iphone应用程序,并得到了应用store 的批准.现在我想为我的应用程序创建不同的主题.有人能帮我吗?关于如何为我的应用创建主题的信息/链接/步骤?

我想为男孩创造一个金属主题,为女孩创造一个粉色主题.再次说到主题,我的意思是,整个应用程序(功能和特性)将保持不变,但取决于用户是谁(男孩或女孩),他/她可以选择他们希望看到的主题.当主题改变时,只有图像/背景/音乐会根据应用的主题而改变.

谢谢!

推荐答案

这是相当困难的,因为应用程序没有css样式表的类似功能.

首先,你需要弄清楚你想对应用程序的哪些部分进行蒙皮,以及何时允许用户交换蒙皮.

我假设你想要改变图像和字体 colored颜色 ,如果用户必须重新启动应用程序来改变皮肤(这将使事情现在变得更简单),也没关系.

创建一个包含所有可蒙皮图像和 colored颜色 的plist.plist将是一本词典,为图像和 colored颜色 提供合理的、主题中立的关键名称(例如,没有称为"红色"的 colored颜色 ,称之为"primaryHeadingColor").图像将是文件名, colored颜色 可以是十六进制字符串,例如FF0000表示红色.

每个主题都有一个plist.

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

+ (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方法中做很多工作.我从来没有发现这是一个问题,但如果你愿意,可以创建一个单独的方法来加载主题词典,并从应用程序的设置代码中调用它).

注意,我是如何从用户默认设置中获取主题列表的名称的.这意味着用户可以在你的首选项中选择一个主题并保存,应用程序将在下次启动时加载该主题.如果没有选择主题,我会输入一个默认的主题名"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上创建一个类别,声明一个名为以下内容的方法:

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

然后,要使用它,您只需替换对[UIImage ImageName:@"foo.png"]的任何调用;带有[UIImage themeimagename:@"foo"];其中foo现在是主题键,而不是实际的图像名称.

好了,这就是你的图片主题.要设置标签 colored颜色 的主题,假设您当前正在通过以下方式设置标签 colored颜色 :

 someLabel.color = [UIColor redColor];

现在,您可以将其替换为:

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

现在,您可能已经注意到UIColor没有"colorWithHexString:"方法——您必须使用类别添加该方法.你可以在谷歌上搜索"UIColor with hex string"解决方案来找到实现这一点的代码,或者我写了一个方便的类别来实现这一点,这里还有更多:https://github.com/nicklockwood/ColorUtils

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

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

就像我们对UIImage做的那样?好主意!

就这样.现在,你可以在应用程序中为任何图像或标签设置主题.您可以使用相同的技巧设置字体名称,或任何其他可能具有主题的视觉属性.

我们只忘记了一件小事...

如果您已经将大多数视图构建为nib(我看没有理由不这样做),那么这些技术将不起作用,因为您的图像名称和字体 colored颜色 隐藏在无法穿透的nib数据中,并且没有在源代码中设置.

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

1) 您可以复制nib的主题副本,然后将nib名称放入主题列表中,并从主题管理器中加载它们.这还不错,只需实现视图控制器的nibName方法,如下所示:

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

请注意我使用视图控制器的类名作为键的巧妙技巧——这将为您节省一些输入,因为您只需使用该方法创建一个基本的ThemeView控制器,并让所有的Themeable视图控制器从中继承.

不过,这种方法确实意味着要维护每个nib的多个副本,如果以后需要更改任何屏幕,这将是一场维护噩梦.

2) 您可以为NIB中的所有ImageView和标签创建IBOutlet,然后在viewDidLoad方法的代码中设置它们的图像和 colored颜色 .这可能是最麻烦的方法,但至少你不需要维护重复的NIB(顺便说一句,这与本地化NIB的问题基本相同,解决方案也基本相同).

3) 您可以创建一个名为ThemeLabel的UILabel自定义子类,在实例化标签时使用上面的代码自动设置字体 colored颜色 ,然后通过在Interface Builder中将标签类设置为ThemeLabel,在nib文件中使用这些ThemeLabel,而不是常规UILabel.不幸的是,如果有多个字体或字体 colored颜色 ,则需要为每个不同的样式创建不同的UILabel子类.

或者,您可以迂回地使用视图标记或accessibilityLabel属性作为样式字典键,这样您就可以拥有单个ThemeLabel类,并在Interface Builder中设置accessibility标签来选择样式.

同样的技巧也适用于ImageView——创建一个名为ThemeImageView的UIImageView子类,在awakeFromNib方法中,该子类使用基于标记或accessibilityLabel属性的主题图像替换图像.

就我个人而言,我最喜欢选项3,因为它节省了编码.选项3的另一个优点是,如果希望能够在运行时交换主题,可以实现一种机制,在该机制中,主题管理器重新加载主题词典,然后向所有主题标签和主题视图广播NSNotification,告诉它们重新绘制自己.这可能只需要额外的15行代码.

总之,你有一个完整的iOS应用主题化解决方案.不客气!

更新:

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

更新2:

从iOS 6开始,现在iOS中内置了一个有限的蒙皮系统,允许您使用名为UIAppearance proxy的属性一次性对给定控件类的所有实例进行蒙皮(关于UIhere有一个很好的教程).值得判断的是,这是否足以满足您的蒙皮需求,但如果不能满足,我上面介绍的解决方案仍然可以很好地工作,可以替代使用,或者与UIAppearance结合使用.

Objective-c相关问答推荐

Objective-C:如何向 NSURL 添加查询参数?

应用程序终止时处理推送通知

Xcode 7 警告:目标文件是为比链接更新的 iOS 版本构建的

为什么 requestWhenInUseAuthorization 不提示用户访问该位置?

iOS 上 64 位的 BOOL

Objective-C 中是否存在强类型集合?

类在两者中都实现.将使用两者之一

将 UIColor 保存到 NSUserDefaults 并从中加载

iOS 正确使用 @weakify(self) 和 @strongify(self)

在 UILabel 中垂直对齐文本(注意:使用 AutoLayout)

如何更改图像 tintColor

所有异常断点在模拟器上无缘无故停止

UITableView 在半透明的导航栏下

选择 UITableViewCell 时如何进行推送

UITextField secureTextEntry 带有自定义字体的项目符号?

UIRefreshControl - 在 iOS 7 中 pull 刷新

围绕其中心旋转 UIView 保持其大小

UICollectionView 自动调整高度

如何更改 UICollectionView 中的滚动方向?

UICollectionView 更新单个单元格