iOS app換膚

app 換膚

關(guān)于app換膚的幾種方式

本地?fù)Q膚

本地?fù)Q膚,是通過(guò)包里面自身已經(jīng)擁有的圖片和顏色配置,對(duì)視圖以及各控件切換主題色。
優(yōu)點(diǎn)是工作量相對(duì)較少,不需要后臺(tái)人員配合。
缺點(diǎn)是局限性比較大,必須通過(guò)發(fā)包的形式才能更新最新的皮膚顏色,也不能根據(jù)節(jié)日更換app主題。

遠(yuǎn)程換膚

遠(yuǎn)程換膚,是通過(guò)后臺(tái)配置的方式,下載新的皮膚對(duì)app重新布局。也可以在app當(dāng)天的第一次啟動(dòng)時(shí),發(fā)送請(qǐng)求給后臺(tái),通過(guò)后臺(tái)的服務(wù)器時(shí)間,緩存最新的節(jié)日皮膚。并在節(jié)日當(dāng)天換上最新的皮膚。
優(yōu)點(diǎn)是可以靈活配置各種皮膚,并且也不會(huì)占用太多的安裝包大小。
缺點(diǎn)是工作量大,耗時(shí)長(zhǎng),需要后臺(tái)人員配合。

換膚方案

app換膚,有多種途徑實(shí)現(xiàn)換膚的效果,以下所敘的是通過(guò)runtime給UIView添加一個(gè)屬性字典,在屬性字典中設(shè)置可變皮膚的特性。再采用通知的方式,讓每個(gè)控件去刷新自身,并且由自身控制生命周期。從而實(shí)現(xiàn)本地?fù)Q膚的效果,并且兼容后續(xù)添加遠(yuǎn)程換膚。

首先設(shè)置存取皮膚主題的plist文件,默認(rèn)添加幾個(gè)皮膚方案。再新建一個(gè)類(lèi)控制皮膚切換時(shí)更改顏色和圖片

+ (UIImage *)setSkinImageWithStr:(NSString *)str
{
     // 獲取plist里面的數(shù)據(jù)
    NSDictionary * dict = [NSString getDicWithKey:@"Skin.plist"];
    if ([dict.allKeys containsObject:@"selectColor"])
    {
        NSString * key = [dict objectForKey:@"selectColor"];
        return [UIImage imageNamed:[NSString stringWithFormat:@"%@_%@", str, key]];
    }
    
    return nil;
}

+ (UIColor *)setSkinColorWithStr:(NSString *)str
{
    NSDictionary * dict = [NSString getDicWithKey:@"Skin.plist"];
    if ([dict.allKeys containsObject:@"selectColor"])
    {
        NSString * key = [dict objectForKey:@"selectColor"];
        NSDictionary * dic = [dict objectForKey:key];
        NSString * colorStr = [dic objectForKey:@"color"];
        return [UIColor sam_colorWithHex:colorStr];
    }
    return [UIColor clearColor];
}

給UIView和UITabbarItem添加類(lèi)別,利用runtime添加themeMap的屬性

static void *kUIView_ThemeMap;
static void *kUIView_DeallocHelper;

@implementation UITabBarItem (UIConfig)

- (void)setThemeMap:(NSDictionary *)themeMap
{
    objc_setAssociatedObject(self, &kUIView_ThemeMap, themeMap, OBJC_ASSOCIATION_COPY_NONATOMIC);
    
    if (themeMap) {
        @autoreleasepool {
            // Need to removeObserver in dealloc
            if (objc_getAssociatedObject(self, &kUIView_DeallocHelper) == nil) {
                __unsafe_unretained typeof(self) weakSelf = self; // NOTE: need to be __unsafe_unretained because __weak var will be reset to nil in dealloc
                id deallocHelper = [self addDeallocBlock:^{
                    NSLog(@"deallocing %@", weakSelf);
                    [[NSNotificationCenter defaultCenter] removeObserver:weakSelf];
                }];
                objc_setAssociatedObject(self, &kUIView_DeallocHelper, deallocHelper, OBJC_ASSOCIATION_ASSIGN);
            }
            
            [[NSNotificationCenter defaultCenter] removeObserver:self name:kThemeDidChangeNotification object:nil];
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(themeChanged) name:kThemeDidChangeNotification object:nil];
            [self themeChanged];
        }
    }
    else {
        [[NSNotificationCenter defaultCenter] removeObserver:self name:kThemeDidChangeNotification object:nil];
    }
    
}

- (NSDictionary *)themeMap
{
    return objc_getAssociatedObject(self, &kUIView_ThemeMap);
}

添加key值對(duì)應(yīng)UItabbarItem的選中顏色,未選中顏色,選中圖片,未選中圖片

/**
 * 設(shè)置圖片
 */
NSString *kTabBarItemKeyImageName             = @"kTabBarItemKeyImageName";
/**
 * 設(shè)置選中圖片
 */
NSString *kTabBarItemKeySelectedImageName     = @"kTabBarItemKeySelectedImageName";
/**
 * 設(shè)置文字顏色
 */
NSString *kTabBarItemKeyColorName             = @"kTabBarItemKeyColorName";
/**
 * 設(shè)置選中文字顏色
 */
NSString *kTabBarItemKeySelectedColorName     = @"kTabBarItemKeySelectedColorName";

通知監(jiān)聽(tīng)的方法

#define TColor(name) [ChangeSkinManager setSkinColorWithStr:name]
#define TImage(name) [ChangeSkinManager setSkinImageWithStr:name]

- (void)themeChanged
{
    // TODO: performace tuning
    dispatch_async(dispatch_get_main_queue(), ^{
        [self changeTheme];
    });
}

- (void)changeTheme
{
    NSDictionary *map = self.themeMap;
    if (map[kTabBarItemKeyImageName])
    {
        self.image = TImage(map[kTabBarItemKeyImageName]);
    }
    if (map[kTabBarItemKeySelectedImageName])
    {
        self.selectedImage = TImage(map[kTabBarItemKeySelectedImageName]);
    }
    if (map[kTabBarItemKeyColorName])
    {
        [self setTitleTextAttributes:[NSMutableDictionary dictionaryWithObjectsAndKeys:TColor(map[kTabBarItemKeyColorName]) ,NSForegroundColorAttributeName, nil] forState:UIControlStateNormal];
    }
    if (map[kTabBarItemKeySelectedColorName])
    {
        [self setTitleTextAttributes:[NSMutableDictionary dictionaryWithObjectsAndKeys:TColor(map[kTabBarItemKeySelectedColorName]) ,NSForegroundColorAttributeName, nil] forState:UIControlStateSelected];
    }
}

在AppDelegate設(shè)置tabbar的時(shí)候

OneViewController * oneVC = [[OneViewController alloc] init];
    UINavigationController * oneNav = [[UINavigationController alloc] initWithRootViewController:oneVC];
    oneNav.tabBarItem.title = @"第一頁(yè)";
    [oneNav.tabBarItem  setTitlePositionAdjustment:UIOffsetMake(0, -3)];
    
    // @""里面設(shè)置plist文件里面自定義的key
    oneNav.tabBarItem.themeMap = @{
                                   kTabBarItemKeyColorName:@"",
                                   kTabBarItemKeySelectedColorName:[ChangeSkinManager setSkinColorWithStr:@""]
                                   };

最后在更換主題時(shí),發(fā)送通知就可以了

- (void)changeSkin:(UIButton *)button
{
    NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject] ;
    NSString *infoFilePath = [cachesPath stringByAppendingPathComponent:@"Skin.plist"];
    NSDictionary * dic = [NSString getDicWithKey:@"Skin.plist"];
    [dic setValue:@"red" forKey:@"selectColor"];
    [dic writeToFile:infoFilePath atomically:YES];
    [[NSNotificationCenter defaultCenter] postNotificationName:kThemeDidChangeNotification object:nil];
}

總結(jié)

如需要實(shí)現(xiàn)遠(yuǎn)程換膚,還需要添加后臺(tái)支持,下載之后添加到plist文件,再切換。

demo地址:https://github.com/LKY7748/ChangeSkinDemo

參考資料:https://github.com/yanjunz/ThemeManager

把工程重新整理了一遍,可以下載查看了。。。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本地?fù)Q膚 本地?fù)Q膚,是通過(guò)包里面自身已經(jīng)擁有的圖片和顏色配置,對(duì)視圖以及各控件切換主題色。 優(yōu)點(diǎn)是工作量相對(duì)較少,...
    軟件iOS開(kāi)發(fā)閱讀 2,214評(píng)論 1 0
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,355評(píng)論 25 708
  • WebSocket-Swift Starscream的使用 WebSocket 是 HTML5 一種新的協(xié)議。它實(shí)...
    香橙柚子閱讀 24,832評(píng)論 8 183
  • “我的帽子丟了?!?我對(duì)我的同伴們說(shuō) 沿著來(lái)路往回找 大家十分熱情 公園各個(gè)角落都找了個(gè)遍 當(dāng)我們?cè)俅螕肀г谝黄鸾?..
    scumalapert閱讀 255評(píng)論 0 0
  • 木木sani閱讀 138評(píng)論 0 0

友情鏈接更多精彩內(nèi)容