Jest to dość trudne, ponieważ aplikacje nie mają odpowiednika arkusza stylów CSS.
Najpierw musisz ustalić, które części aplikacji chcesz skórki, i kiedy chcesz zezwolić użytkownikowi na zamianę skórek.
Zamierzam założyć, że chcesz zmienić obrazy i kolory czcionek, i że jest to w porządku, jeśli użytkownik musi ponownie uruchomić aplikację, aby zmienić skórkę (co na razie uprości to).
Tworzenie pliku plist zawierającego wszystkie możliwe do skriningu obrazy i kolory. Plik plist będzie słownikiem z sensownymi, tematycznie neutralnymi nazwami klawiszy dla obrazów i kolorów (np. Nie ma koloru o nazwie "czerwony", nazywamy go "primaryHeadingColor"). Obrazy będą nazwami plików, a kolory mogą być ciągami szesnastkowymi, np. FF0000 na czerwono.
Będziesz miał jeden plik na każdy motyw.
Utwórz nową klasę o nazwie ThemeManager i sprawiają, że pojedyncza dodając następującą metodę:
+ (ThemeManager *)sharedManager
{
static ThemeManager *sharedManager = nil;
if (sharedManager == nil)
{
sharedManager = [[ThemeManager alloc] init];
}
return sharedManager;
}
Klasa ThemeManager będzie miał właściwość NSDictionary nazwie „style”, a w metodzie init Ci załadować motyw w swoich stylach słownika tak:
- (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;
}
(Uwaga: niektórzy ludzie nie lubią robić dużo pracy wewnątrz metody init, nigdy nie okazało się, że to problem, ale jeśli wolisz. utwórz osobną metodę ładowania słownika motywów i ca Zrób to z kodu instalacji twojej aplikacji).
Zauważ, jak otrzymuję nazwę pliku plist z domyślnych ustawień użytkownika. Oznacza to, że użytkownik może wybrać motyw w swoich preferencjach i zapisać go, a aplikacja załaduje ten motyw przy następnym uruchomieniu. Wstawiłem domyślną nazwę motywu "domyślną", jeśli nie wybrano żadnego motywu, więc upewnij się, że masz plik motywu default.plist (lub zmień @ "domyślny" w kodzie na cokolwiek domyślnie nazywa się plist domyślny plist).
Po załadowaniu motywu należy go użyć; Zakładam, że Twoja aplikacja ma różne obrazy i etykiety tekstowe. Jeśli ładujesz i umieszczasz je w kodzie, ta część jest łatwa. Jeśli robisz to w stalówkach, to jest trochę trudniej, ale wyjaśnię, jak sobie z tym poradzić później.
Teraz normalnie byś załadować obraz mówiąc:
UIImage *image = [UIImage imageNamed:@"myImage.png"];
Ale jeśli chcesz, że obraz będzie themable, będziesz teraz trzeba załadować go mówiąc
NSDictionary *styles = [ThemeManager sharedManager].styles;
NSString *imageName = [styles objectForKey:@"myImageKey"];
UIImage *image = [UIImage imageNamed:imageName];
które będą spójrz w swój plik motywu na tematowy obraz, który pasuje do klucza "myImageKey" i załaduje go. W zależności od załadowanego pliku motywu otrzymasz inny styl.
Używasz tych trzech linii, więc możesz chcieć zawinąć je w funkcję. Świetnym pomysłem byłoby, aby utworzyć kategorię na UIImage który deklaruje metodę nazywa się coś takiego:
+ (UIImage *)themeImageNamed:(NSString *)key;
Następnie użyć go można po prostu zastąpić żadnych połączeń do [UIImage imageNamed: @ „foo.png”]; z [UIImage themeImageNamed: @ "foo"]; gdzie foo jest teraz kluczem motywu zamiast rzeczywistą nazwą obrazu.
OK, więc to wszystko do tworzenia zdjęć. Z tematyką kolory etykiet, załóżmy, że jesteś obecnie ustawienie kolory etykiet, mówiąc:
someLabel.color = [UIColor redColor];
będzie teraz zastąpić że z:
NSDictionary *styles = [ThemeManager sharedManager].styles;
NSString *labelColor = [styles objectForKey:@"myLabelColor"];
someLabel.color = [UIColor colorWithHexString:labelColor];
Teraz można zauważyć, że nie ma UIColor metoda "colorWithHexString:" - musisz dodać to za pomocą kategorii. Możesz używać Google, by znaleźć rozwiązanie "UIColor z ciągiem szesnastkowym", aby znaleźć kod do tego celu, lub napisałem przydatną kategorię, która to robi i nieco więcej tutaj: https://github.com/nicklockwood/ColorUtils
Jeśli zwracałeś uwagę, to będziesz również myśleć, że zamiast pisać te trzy linie w kółko, to dlaczego nie dodać metodę UIColor nazwie:
+ (UIColor *)themeColorNamed:(NSString *)key;
Tak jak zrobiliśmy z UIImage? Świetny pomysł!
To wszystko. Teraz możesz kierować dowolny obraz lub etykietę w swojej aplikacji. Możesz użyć tej samej sztuczki, aby ustawić nazwę czcionki lub dowolną liczbę innych potencjalnie możliwych do wyświetlenia właściwości wizualnych.
Jest tylko jeden mały rzeczą zapomnieliśmy ...
Jeśli zbudowana większość swoich poglądów jak śruta (i nie widzę powodu, dlaczego nie będzie), a następnie techniki te nie będą do pracy, ponieważ nazwy obrazów i kolory czcionek są ukryte w danych nieprzeniknionych stalówek i nie są ustawione w kodzie źródłowym.
Istnieje kilka metod, aby rozwiązać ten:
1) Można dokonać duplikaty tematycznych swoich stalówki, a następnie umieścić stalówki nazwy w swojej motyw plist i załadować je od swojego menedżera motywu. To nie jest tak źle, po prostu wdrożyć metodę nibName swojego widoku kontrolerów tak:
- (NSString *)nibName
{
NSDictionary *styles = [ThemeManager sharedManager].styles;
return [styles objectForKey:NSStringFromClass([self class])];
}
Wskazówka mój zgrabny sztuczki z użyciem nazwy klasy kontrolera widoku jako klucz - to pozwoli Ci zaoszczędzić trochę pisania, ponieważ można po prostu zrób podstawową funkcję ThemeViewController za pomocą tej metody, a wszystkie dziedziczne kontrolery widoku dziedziczą z niej.
Takie podejście oznacza jednak zachowanie wielu kopii każdej stalówki, co jest koszmarem dla konserwacji, jeśli trzeba później zmienić ekrany.
2) Można utworzyć IBOutlety dla wszystkich obrazów i etykiet w stalówkach, a następnie ustawić ich obrazy i kolory w kodzie w metodzie viewDidLoad. To prawdopodobnie najbardziej uciążliwe podejście, ale przynajmniej nie masz duplikatów do utrzymania (jest to zasadniczo ten sam problem, co lokalizacja lokalnych końcówek stalówki, i prawie takie same opcje rozwiązania).
3) Można utworzyć niestandardową podklasę UILabel o nazwie ThemeLabel, która automatycznie ustawi kolor czcionki za pomocą powyższego kodu, gdy etykieta zostanie utworzona, a następnie użyj tych etykiet tematycznych w plikach nib zamiast zwykłych etykiet UILabels, ustawiając klasę etykieta do ThemeLabel w Interface Builder. Niestety, jeśli masz więcej niż jedną czcionkę lub kolor czcionki, musisz utworzyć inną podklasę UILabel dla każdego innego stylu.
Albo możesz być przebiegły i użyć czegoś takiego jak znacznik widoku lub właściwość accessLabel jako klucz słownika stylu, abyś mógł mieć jedną klasę ThemeLabel i ustawić etykietę dostępności w Konstruktorze interfejsów, aby wybrać styl.
Ta sama sztuczka może działać w przypadku ImageViews - utwórz podklasę UIImageView o nazwie ThemeImageView, która w metodzie awakeFromNib zastępuje obraz obrazem kompozycji na podstawie właściwości tag lub accessibilityLabel.
Osobiście lubię opcję 3 najlepiej, ponieważ oszczędza na kodowaniu. Kolejną zaletą opcji 3 jest to, że jeśli chcesz mieć możliwość zamiany motywów w środowisku wykonawczym, możesz zaimplementować mechanizm, w którym menedżer kompozycji ponownie ładuje słownik kompozycji, a następnie nadaje NSNotification wszystkim etykietom ThemeLabels i ThemeImageViews, nakazując im przerysowanie. To prawdopodobnie zajmie tylko około 15 linii kodu.
W każdym razie istnieje kompletne rozwiązanie do motywowania aplikacji dla systemu iOS. Nie ma za co!
UPDATE:
Jak z iOS 5, to teraz można ustawić atrybuty niestandardowe przez keypath w konstruktorze Interface, co oznacza, że nie jest już konieczne, aby utworzyć widok podklasy dla każdej nieruchomości themable lub nadużywają tag lub accessibilityLabel do wyboru stylów. Podajcie swoją podklasę UILabel lub UIImageView własność string, aby wskazać, który klawisz motywu powinien użyć z pliku plist, a następnie ustawić tę wartość w IB.
UPDATE 2:
W iOS 6, jest teraz ograniczona systemu skórek wbudowana w iOS, która pozwala na używanie właściwość o nazwie proxy UIAppearance do skóry wszystkich wystąpień danej klasy sterowania naraz (Istnieje dobry samouczek dotyczący interfejsów API UIAppearance here). Warto sprawdzić, czy jest to wystarczające dla twoich potrzeb skórowania, ale jeśli nie, rozwiązanie, które opisałem powyżej, nadal działa dobrze i może być użyte zamiast tego lub w połączeniu z UIAppearance.
Co masz dokładnie na myśli? Co chcesz "motywować"? –
Jestem prawie pewny, że miał na myśli tematy takie jak w Windowsie! – Ravi
To pytanie nie powinno zostać zamknięte, jest to całkowicie uzasadnione pytanie z interesującym zestawem możliwych rozwiązań technicznych, a większość ludzi rozumie znaczenie "tematu" w kontekście aplikacji. –