it-swarm.com.ru

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

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

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

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

54
pat

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

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

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

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

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

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

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

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

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

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

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? Отличная идея!

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Обновление:

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

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

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

129
Nick Lockwood