2012-01-19 2 views
52

У меня есть приложение iphone, готовое и одобренное магазином приложений. Теперь я хочу создать разные темы для своего приложения. Может кто-то, пожалуйста, помогите мне, с информацией/ссылками/шагами о том, как создавать темы для моего приложения?Как создать несколько тем/скинов для iphone-приложений?

Я хочу создать металлическую тему для мальчиков и розовую тему для девочек. Снова по теме я имею в виду, что все приложение (функции и функциональность) останется неизменным, но в зависимости от того, кем является пользователь (мальчик или девочка), он может выбрать тему, которую они хотят видеть. И когда тема меняется, только изображения/Фон/музыка будут меняться в соответствии с применяемой темой.

Большое спасибо!

+0

Что вы имеете в виду именно по темам? Что вы хотите «тему»? –

+3

Я уверен, что он имел в виду темы, как в Windows-темы! – Ravi

+47

Этот вопрос не должен был быть закрыт, это совершенно законный вопрос с интересным набором возможных технических решений, и большинство людей понимают значение темы в контексте приложения. –

ответ

122

Это довольно сложно, поскольку приложения не имеют эквивалента таблицы стилей css.

Прежде всего вам нужно выяснить, какие части приложения вы хотите использовать, и когда вы хотите, чтобы пользователь мог менять скины.

Я собираюсь предположить, что вы хотите изменить цвета изображений и шрифтов, и что это нормально, если пользователь должен перезапустить приложение, чтобы изменить скин (теперь это упростит).

Создайте plist, содержащий все ваши скин-изображения и цвета. Плистом будет словарь с разумными, нейтральными ключевыми именами темы для изображений и цветов (например, цвет не называется «красный», назовите его «primaryHeadingColor»). Изображения будут именами файлов, а цветами могут быть шестнадцатеричные строки, например. FF0000 для красного.

У вас будет один слой для каждой темы.

Создать новый класс ThemeManager и сделать его синглтон, добавив следующий метод:

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

Класс ThemeManager будет иметь NSDictionary свойства «стили», и в методе инициализации вы загрузите тема в ваши стили словаря, как это:

- (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; 
} 

(Примечание: некоторые люди не любят делать много работы внутри метода инициализации я никогда не нашел, что это будет проблемой, но если вы предпочитаете,. создать отдельный метод загрузки словаря тем это из кода установки вашего приложения).

Обратите внимание, как я получаю имя для темы из пользовательских значений по умолчанию. Это означает, что пользователь может выбрать тему в своих настройках и сохранить ее, и приложение будет загружать эту тему при следующем запуске. Я поместил название темы по умолчанию «default», если не выбрана ни одна тема, поэтому убедитесь, что у вас есть файл темы default.plist (или измените значение @ «по умолчанию» в коде на то, что фактически выбранный вами слой темы по умолчанию).

Теперь, когда вы загрузили свою тему, вам нужно ее использовать; Я предполагаю, что ваше приложение имеет различные изображения и текстовые метки. Если вы загружаете и кладете их в код, то эта часть проста. Если вы делаете это в nibs, то это немного сложнее, но я объясню, как с этим справиться позже.

Теперь обычно вы бы загрузить изображение, говоря:

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

Но если вы хотите, чтобы изображение было themable, вам теперь нужно, чтобы загрузить его, говоря

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

, который будет посмотрите в своем файле темы для тематического изображения, которое соответствует ключу «myImageKey» и загрузит его. В зависимости от того, какой файл темы вы загрузили, вы получите другой стиль.

Вы будете использовать эти три строки так, чтобы их можно было обернуть в функцию. Отличная идея бы создать категорию на UIImage, который объявляет метод называется что-то вроде:

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

Затем, чтобы использовать его, вы можете просто заменить все вызовы на [UIImage imageNamed: @ «foo.png»]; с [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 для решений «UIColor с шестнадцатеричной строкой», чтобы найти код для этого, или я написал удобную категорию, которая делает это и немного больше здесь: https://github.com/nicklockwood/ColorUtils

Если вы обратили внимание, также думать, что вместо того, чтобы писать эти три линии снова и снова, почему бы не добавить метод UIColor под названием:

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

Так же, как мы делали с UIImage? Отличная идея!

Вот и все. Теперь вы можете пометить любое изображение или ярлык в своем приложении. Вы можете использовать тот же трюк, чтобы задать имя шрифта или любое количество других потенциально видимых визуальных свойств.

Там только одна крошечная вещь, которую мы забыли ...

Если вы построили большую часть ваших взглядов, как наконечниками (и я не вижу причин, почему вы не захотели), то эти методы не собираются работать, потому что ваши имена изображений и цвета шрифтов зарываются внутри непроницаемых данных nib и не устанавливаются в исходном коде.

Есть несколько подходов для решения этой проблемы:

1) Вы могли бы сделать дубликаты тематических копии наконечников, а затем положить перо имен в вашей теме списке свойств и загружать их из своего менеджера темы. Это не так уж плохо, просто реализовать метод nibName ваших контроллеров зрения, как это:

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

Обратите внимание, мой ловкий трюк использования имени класса контроллера представления как ключ - это сэкономит вам немного печатать, потому что вы можете просто создайте базовый ThemeViewController с этим методом и унаследуйте от него все ваши контролируемые контроллеры представлений.

Этот подход означает поддержание нескольких копий каждого наконечника, хотя это кошмар обслуживания, если вам нужно изменить какие-либо экраны позже.

2) Вы можете сделать IBOutlets для всех изображений и ярлыков в ваших наконечках, а затем установить их изображения и цвета в коде в методе viewDidLoad. Это, вероятно, самый громоздкий подход, но по крайней мере у вас нет дублирующих наконечников для поддержки (это, по сути, та же проблема, что и локализация nibs btw, и почти такие же варианты решения).

3) Вы можете создать пользовательский подкласс UILabel, называемый ThemeLabel, который автоматически устанавливает цвет шрифта с помощью кода выше, когда эта метка создается, а затем используйте эти ThemeLabels в ваших файлах nib вместо обычных UILabels, установив класс наклейте на ThemeLabel в Interface Builder. К сожалению, если у вас более одного шрифта или шрифта, вам нужно создать другой подкласс UILabel для каждого другого стиля.

Или вы можете быть хитрыми и использовать что-то вроде тега вида или свойства accessibilityLabel как ключ словаря стиля, чтобы вы могли иметь один класс ThemeLabel и установить метку доступности в Interface Builder, чтобы выбрать стиль.

Такой же трюк может работать для ImageViews - создать подкласс UIImageView под названием ThemeImageView, который в методе awakeFromNib заменяет изображение образ темы на основе тега или свойства accessibilityLabel.

Лично мне нравится вариант 3, потому что он экономит на кодировании. Еще одним преимуществом варианта 3 является то, что если вы хотите иметь возможность обменивать темы во время выполнения, вы можете реализовать механизм, в котором ваш диспетчер темы загружает словарь темы, а затем транслирует NSNotification ко всем ThemeLabels и ThemeImageViews, говорящим им перерисовывать себя. Вероятно, это займет всего лишь 15 строк кода.

В любом случае, у вас есть полное приложение для iOS-приложений. Пожалуйста!

UPDATE:

С прошивкой 5, теперь можно установить пользовательские атрибуты с помощью ключевого ресурса в Interface Builder, а это означает, что это больше не нужно, чтобы создать вид подкласса для каждого themable собственности или злоупотребляют тег или accessibilityLabel для выбора стилей. Просто дайте вашему подклассу UILabel или UIImageView свойство string, чтобы указать, какой ключ темы он должен использовать из plist, а затем установить это значение в IB.

UPDATE 2:

С прошивкой 6, в настоящее время ограниченной система обесшкуривания встроены в прошивку, что позволяет использовать это свойство называется UIAppearance прокси кожу всех экземпляров данного класса управления сразу (есть хороший учебник по API UIAppearance here). Стоит проверить, достаточно ли этого для ваших потребностей в скиннинге, но если это не так, решение, которое я изложил выше, все еще работает хорошо и может использоваться вместо этого или в сочетании с UIAppearance.

+3

Его действительно удивительное спасибо nik – sinh99

+4

О, мой БОГ! Я думаю, что это лучшее, лучшее, лучшее руководство/ответ/помощь/учебник, который я когда-либо читал. Еще не дошли до конца, но продолжайте удивляться тому, как вы потратили время, чтобы объяснить вещи так красиво простым способом. Поистине удивительно! Я желаю, чтобы люди в каналах IRC тоже были хороши. Большое спасибо. – Neeku

+1

Ницца, спасибо +1 – TonyMkenu

Смежные вопросы