web-dev-qa-db-ja.com

iPhoneアプリ用に複数のテーマ/スキンを作成する方法

Iphoneアプリを準備して、アプリストアで承認しました。次に、アプリにさまざまなテーマを作成します。アプリのテーマの作成方法に関する情報/リンク/手順を教えてください。

BoysにはMetalテーマを、GirlsにはPinkテーマを作成します。繰り返しますが、テーマによって、アプリ全体(機能と機能)は同じままになりますが、ユーザーが誰であるか(男の子または女の子)に応じて、ユーザーは見たいテーマを選択できます。テーマが変更されると、適用されるテーマに応じて画像/背景/音楽のみが変更されます。

どうもありがとう!

55
pat

アプリにはCSSスタイルシートに相当するものがないため、これは非常に困難です。

まず、アプリのどの部分にスキンを適用するか、そしていつユーザーがスキンを交換できるようにするかを決める必要があります。

画像とフォントの色を変更したい、そしてユーザーがスキンを変更するためにアプリを再起動しなければならないのであれば大丈夫だと仮定します(これで今はもっと簡単になります)。

すべてのスキン可能な画像と色を含むplistを作成します。 plistは、画像と色の意味のあるテーマニュートラルキー名を持つ辞書になります(たとえば、「赤」と呼ばれる色を持たず、「primaryHeadingColor」と呼びます)。画像はファイル名になり、色は16進文字列になります。赤の場合はFF0000。

テーマごとに1つのplistがあります。

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メソッド内で多くの作業を行うことを好まない人もいます。これが問題になることは一度もありませんが、必要に応じて、テーマ辞書をロードしてアプリから呼び出す別のメソッドを作成しますセットアップコード)。

ユーザーのデフォルトからテーマplistの名前を取得していることに注目してください。これは、ユーザーが設定でテーマを選択して保存できることを意味し、アプリは次回起動時にそのテーマをロードします。テーマが選択されていない場合は、デフォルトのテーマ名「default」を入力しました。そのため、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」に一致するテーマ画像が検索され、ロードされます。どのテーマファイルを読み込んだかによって、異なるスタイルが得られます。

これらの3行を頻繁に使用するので、関数でそれらをラップすることができます。素晴らしいアイデアは、次のようなメソッドを宣言するUIImageにカテゴリを作成することです。

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

それを使用するには、[UIImage imageNamed:@ "foo.png"]への呼び出しを置き換えるだけです。 with [UIImage themeImageNamed:@ "foo"];ここで、fooは実際の画像名ではなくテーマキーです。

さて、画像のテーマはこれで終わりです。ラベルの色をテーマにするには、次のように言って現在ラベルの色を設定しているとします。

 someLabel.color = [UIColor redColor];

これを次のように置き換えます。

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

UIColorにはメソッド "colorWithHexString:"がないことに気づいたかもしれません-カテゴリを使用して追加する必要があります。 Googleで「16進数文字列を使用したUIColor」ソリューションを探して、それを行うコードを見つけることができます。または、それを行う便利なカテゴリをもう1つ書いています。 https://github.com/nicklockwood/ColorUtils

注意を払っていれば、これらの3行を何度も書くのではなく、UIColorにメソッドを追加してみてはいかがでしょうか。

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

UIImageで行ったように?いい案!

以上です。これで、アプリ内の任意の画像またはラベルをテーマにできます。同じトリックを使用して、フォント名、またはその他のテーマ設定可能な視覚プロパティをいくつでも設定できます。

忘れてしまった小さなことが1つだけあります...

ビューのほとんどをペン先として作成した場合(そして、そうしない理由はないと思います)、これらの手法は機能しません。画像名とフォントの色は、突き通せないペン先データの中に埋め込まれていて、ソースコードで設定します。

これを解決する方法はいくつかあります。

1)ペン先のテーマ別コピーを作成し、ペン先名をテーマplistに入れて、テーママネージャーから読み込むことができます。これはそれほど悪くありません。次のようにView ControllerのnibNameメソッドを実装するだけです。

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

ビューコントローラーのクラス名をキーとして使用する私の巧妙なトリックに注目してください-そのメソッドでベースのThemeViewControllerを作成し、すべてのテーマ可能なビューコントローラーにそれを継承させることができるので、入力を節約できます。

ただし、このアプローチは各ペン先の複数のコピーを維持することを意味します。これは、後で画面を変更する必要がある場合のメンテナンスの悪夢です。

2)ペン先のすべてのimageViewとラベルのIBOutletsを作成し、viewDidLoadメソッドのコードでそれらの画像と色を設定できます。これはおそらく最も面倒なアプローチですが、少なくとも、維持する重複ニブはありません(これは基本的に、ニブのローカライズと同じ問題であり、ほとんど同じソリューションオプションです)。

3)ラベルがインスタンス化されると、上記のコードを使用して自動的にフォントの色を設定するThemeLabelと呼ばれるUILabelのカスタムサブクラスを作成し、ラベルのクラスをThemeLabelに設定することにより、通常のUILabelsの代わりにこれらのThemeLabelsをnibファイルで使用できますインターフェイスビルダー。残念ながら、複数のフォントまたはフォントの色がある場合は、スタイルごとに異なるUILabelサブクラスを作成する必要があります。

または、不正なもので、ビュータグやaccessibilityLabelプロパティなどをスタイルディクショナリキーとして使用して、単一のThemeLabelクラスを作成し、Interface Builderでアクセシビリティラベルを設定してスタイルを選択できるようにすることもできます。

同じトリックがImageViewsでも機能します-awakeFromNibメソッドで、タグまたはaccessibilityLabelプロパティに基づくテーマ画像で画像を置き換えるThemeImageViewというUIImageViewサブクラスを作成します。

個人的には、オプション3が一番好きです。なぜなら、コーディングが節約できるからです。オプション3のもう1つの利点は、実行時にテーマを交換できるようにしたい場合、テーママネージャーがテーマ辞書を再読み込みし、NSNotificationをすべてのThemeLabelsおよびThemeImageViewsにブロードキャストして、自分自身を再描画するメカニズムを実装できることです。おそらく、余分な15行のコードだけで済みます。

とにかく、完全なiOSアプリテーマソリューションがあります。どういたしまして!

更新:

IOS 5では、Interface BuilderでkeyPathによってカスタム属性を設定できるようになりました。つまり、テーマ設定可能なプロパティごとにビューサブクラスを作成したり、スタイルを選択するためにタグやaccessibilityLabelを悪用したりする必要がなくなりました。 UILabelまたはUIImageViewサブクラスに文字列プロパティを与えて、plistから使用するテーマキーを示し、その値をIBに設定するだけです。

更新2:

IOS 6の時点で、iOSに組み込まれた限定的なスキニングシステムがあり、UIAppearance proxyと呼ばれるプロパティを使用して、一度に制御クラスを指定します(UIAppearance APIに関する良いチュートリアルがあります here )。これがスキニングのニーズに十分であるかどうかを確認する価値がありますが、そうでない場合は、上で概説したソリューションはまだうまく機能し、代わりに、またはUIAppearanceと組み合わせて使用​​できます。

130
Nick Lockwood