program tip

iPhone 앱용 여러 테마 / 스킨을 만드는 방법은 무엇입니까?

radiobox 2021. 1. 6. 07:59
반응형

iPhone 앱용 여러 테마 / 스킨을 만드는 방법은 무엇입니까?


iPhone 앱이 준비되어 있고 앱 스토어에서 승인했습니다. 이제 내 앱에 대해 다른 테마를 만들고 싶습니다. 누군가 내 앱의 테마를 만드는 방법에 대한 정보 / 링크 / 단계와 함께 나를 도와 줄 수 있습니까?

남아를위한 메탈 테마와 소녀를위한 핑크 테마를 만들고 싶습니다. 다시 한 번 테마 별로는 전체 앱 (특징 및 기능)이 동일하게 유지되지만 사용자가 누구인지 (남자 또는 여자)에 따라보고 싶은 테마를 선택할 수 있습니다. 그리고 테마 변경시 적용된 테마에 따라 이미지 / 배경 / 음악 만 변경됩니다.

감사합니다!


앱에 CSS 스타일 시트와 동일한 기능이 없기 때문에 이것은 매우 어렵습니다.

먼저 스킨을 적용 할 앱 부분과 사용자가 스킨을 교체 할 수있는시기를 결정해야합니다.

이미지와 글꼴 색상을 변경하고 싶다고 가정하고 사용자가 스킨을 변경하기 위해 앱을 다시 시작해야하더라도 괜찮습니다 (지금은 더 간단 해집니다).

모든 스킨 가능 이미지와 색상을 포함하는 plist를 만듭니다. plist는 이미지와 색상에 대한 감각적이고 테마 중립적 인 키 이름을 가진 사전이됩니다 (예 : "빨간색"이라는 색상이 없으면 "primaryHeadingColor"라고 함). 이미지는 파일 이름이고 색상은 16 진수 문자열이 될 수 있습니다 (예 : 빨간색의 경우 FF0000).

각 테마에 대해 하나의 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"키와 일치하는 테마 이미지를 찾아로드합니다. 로드 한 테마 파일에 따라 다른 스타일을 얻을 수 있습니다.

이 세 줄을 많이 사용하므로 함수로 묶을 수 있습니다. 좋은 아이디어는 다음과 같은 메서드를 선언하는 UIImage에 범주를 만드는 것입니다.

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

Then to use it you can just replace any calls to [UIImage imageNamed:@"foo.png"]; with [UIImage themeImageNamed:@"foo"]; where foo is now the theme key instead of the actual image name.

Okay, so that's it for theming your images. To theme your label colours, suppose you're currently setting your label colours by saying:

 someLabel.color = [UIColor redColor];

You would now replace that with:

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

Now you may have noticed that UIColor doesn't have a method "colorWithHexString:" - you'll have to add that using a category. You can Google for "UIColor with hex string" solutions to find code to do that, or I've written a handy category that does that and a bit more here: https://github.com/nicklockwood/ColorUtils

If you've been paying attention you'll also be thinking that instead of writing those three lines over and over, why not add a method to UIColor called:

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

Just like we did with UIImage? Great idea!

So that's it. Now you can theme any image or label in your app. You could use the same trick to set the font name, or any number of other potentially themable visual properties.

There's just one tiny thing we've forgotten...

If you've built most of your views as nibs (and I see no reason why you wouldn't) then these techniques aren't going to work because your image names and font colours are buried inside impenetrable nib data and aren't being set in your source code.

There are a few approaches to solve this:

1) You could make duplicate themed copies of your nibs and then put the nib names in your theme plist and load them from your theme manager. That's not too bad, just implement the nibName method of your view controllers like this:

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

Notice my neat trick of using the class name of the view controller as the key - that will save you some typing because you can just make a base ThemeViewController with that method and have all your themable view controllers inherit from it.

This approach does mean maintaining multiple copies of each nib though, which is a maintenance nightmare if you need to change any screens later.

2) You could make IBOutlets for all of the imageViews and labels in your nibs, then set their images and colors in code in your viewDidLoad method. That's probably the most cumbersome approach, but at least you don't have duplicate nibs to maintain (this is essentially the same problem as localising nibs btw, and pretty much the same solution options).

3) You could create a custom subclass of UILabel called ThemeLabel that automatically sets the font color using the code above when the label is instantiated, then use those ThemeLabels in your nib files instead of regular UILabels by setting the class of the label to ThemeLabel in Interface Builder. Unfortunately if you have more than one font or font colour, you'll need to create a different UILabel subclass for each different style.

Or you could be devious and use something like the view tag or accessibilityLabel property as the style dictionary key so that you can have a single ThemeLabel class and set the accessibility label in Interface Builder to select the style.

The same trick could work for ImageViews - create a UIImageView subclass called ThemeImageView that, in the awakeFromNib method replaces the image with a theme image based on the tag or accessibilityLabel property.

Personally I like option 3 best because it saves on coding. Another advantage of option 3 is that if you wanted to be able to swap themes at runtime, you could implement a mechanism where your theme manager reloads the theme dictionary, then broadcasts an NSNotification to all the ThemeLabels and ThemeImageViews telling them to redraw themselves. That would probably only take about an extra 15 lines of code.

Anyway, there you have a complete iOS app theming solution. You're welcome!

UPDATE:

As of iOS 5, it's now possible to set custom attributes by keyPath in Interface Builder, meaning that it's no longer necessary to create a view subclass for each themable property, or abuse the tag or accessibilityLabel for selecting styles. Just give your UILabel or UIImageView subclass a string property to indicate which theme key it should use from the plist, and then set that value in IB.

UPDATE 2:

As of iOS 6, there is now a limited skinning system built into iOS that allows you to use a property called the UIAppearance proxy to skin all instances of a given control class at once (there's a good tutorial about the UIAppearance APIs here). It's worth checking if this is sufficient for your skinning needs, but if not, the solution I outlined above still works well, and can be used instead, or in combination with UIAppearance.

ReferenceURL : https://stackoverflow.com/questions/8919334/how-to-create-multiple-themes-skins-for-iphone-apps

반응형