Подтвердить что ты не робот

Как создать несколько тем/скинов для приложений iphone?

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

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

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

4b9b3361

Ответ 1

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

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

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

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

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

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

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

Класс ThemeManager будет иметь свойство 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", если не выбрана ни одна тема, поэтому убедитесь, что у вас есть файл темы default.plist(или измените значение @ "по умолчанию" в коде на то, что фактически выбранный вами слой темы по умолчанию).

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

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

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 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 и aren 't устанавливается в вашем исходном коде.

Существует несколько подходов к решению этой проблемы:

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 в интерфейсе Builder. К сожалению, если у вас более одного шрифта или шрифта, вам нужно создать другой подкласс UILabel для каждого другого стиля.

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

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

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

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

UPDATE:

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

ОБНОВЛЕНИЕ 2:

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