使用腳本結(jié)合Xcode的Asset Catalogs功能對圖片和顏色的管理

在Xcode中使用Asset Catalogs大致效果如下圖


asset.png

代碼調(diào)用

UIColor(named: "greenx")

UIImage(named: "Image")

與我們平時(shí)調(diào)用的代碼沒有什么區(qū)別孵运。

這樣調(diào)用代碼里面會(huì)出現(xiàn)很對的硬編碼,會(huì)導(dǎo)致代碼不易維護(hù)惠呼,資源管理也極其不方便导俘。

為了減少硬編碼的對代碼管理帶來的不便可以統(tǒng)一管理資源的硬編碼,創(chuàng)建管理類來維護(hù)這些資源剔蹋。

顏色管理類

import UIKit
extension UIColor {
//start sync tag
    // R: 0.717, G: 0.200 , B: 0.300, A: 1.000                    
    // R: 182  , G: 51    , B: 76   , A: 255                      
    // R: B6   , G: 33    , B: 4C   , A: FF                       
    public static var asdw: UIColor? {                    
        _ = #colorLiteral(red: 0.717, green: 0.200, blue: 0.300, alpha: 1.000)                    
        return UIColor(named: "asdw")                    
    }
        ........
//end sync tag
}

代碼效果


color_code.png

圖片管理類

import UIKit
extension UIImage {
//start sync tag
    public static var folder: UIImage? {        
        _ = #imageLiteral(resourceName: "folder")        
        return UIImage(named: "folder")        
    }
//end sync tag
}

圖片效果


image_code.png

資源的使用就不會(huì)出現(xiàn)硬編碼了

let color = UIColor.asdw
let image = UIImage.folder

但是還是需要我們手動(dòng)去維護(hù)這些個(gè)管理類旅薄,也是一件比較麻煩的事。

我們可以使用Xcode的Run Script來幫助我門來完成這個(gè)管理類的維護(hù)工作,這樣就能幫助我們省去很多的工作量


runscript.png

我們可以使用腳本來幫助我們完成管理類與Assets Catalogs的同步工作少梁,每次編譯時(shí)都會(huì)進(jìn)行一次同步(Run Script的位置決定了腳本的執(zhí)行順序洛口,建議放在Compile Sources的上面),同步后在進(jìn)行代碼的編譯凯沪。

這樣就可以直接知道資源的使用錯(cuò)誤第焰。

下面直接上腳本,這里我用的是Python腳本

顏色同步腳本

import sys
import os
import json

def sync_color_file():
    temp_file = None
    if os.path.exists(color_file_path):
        os.rename(color_file_name, temp_file_name)
        temp_file = open(temp_file_path, 'r')
        color_file = open(color_file_path, "w+")
        while True:
            line = temp_file.readline()
            color_file.write(line)
            if start_tag in line:
                break
    else:
        color_file = open(color_file_path, "w+")
        color_file.write('//\
            \n//  {}\
            \n//  {}\
            \n//\
            \n//  Created by XXXX on 9999/99/99.\
            \n//\
            \n\
            \nimport UIKit\
            \n\
            \nextension UIColor {{\
            \n{}\n'.format(color_file_name, project_name, start_tag))
    color_file.write(analysis_assets())
    start_write_tail = False
    if temp_file:
        while True:
            line = temp_file.readline()
            if end_tag in line:
                start_write_tail = True
            if start_write_tail:
                color_file.write(line)
            if line == '':
                break
        if not start_write_tail:
            color_file.write('\n{}\n}}'.format(end_tag))
        temp_file.close()
        os.remove(temp_file_path)
    else:
        color_file.write('\n{}\n}}'.format(end_tag))
    color_file.close()

def analysis_assets():
    sync_result_str = ''
    for folder, subFolders, files in os.walk("Assets.xcassets"):
        color_name = os.path.basename(folder)
        color_suffix = '.colorset'
        if not color_name.endswith(color_suffix):
            continue
        param_name = color_name.replace(color_suffix, '')
        if param_name in system_color_names:
            print('!!!!!color name is same as system color name <<<{}>>>!!!!! '.format(param_name))
            continue
        if 'Contents.json' not in files:
            continue
        with open(os.path.join(folder, 'Contents.json'), 'r') as load_f:
            load_dict = json.load(load_f)
            for color_item in load_dict['colors']:
                # appearances = color_item.get('appearances', None)
                # idiom = color_item.get('idiom', None)
                color = color_item.get('color', None)
                if not color:
                    continue
                color_components = color['components']
                sync_result_str += '\
                    \n\t// R: {R}, G: {G} , B: {B}, A: {A}\
                    \n\t// R: {R8}, G: {G8} , B: {B8}, A: {A8}\
                    \n\t// R: {RH}, G: {GH} , B: {BH}, A: {AH}\
                    \n\tpublic static var {name}: UIColor? {{\
                    \n\t\t_ = #colorLiteral(red: {R}, green: {G}, blue: {B}, alpha: {A})\
                    \n\t\treturn UIColor(named: "{name}")\
                    \n\t}}\n'.format(name=param_name,
                                     R=color_to_float(color_components['red']),
                                     G=color_to_float(color_components['green']),
                                     B=color_to_float(color_components['blue']),
                                     A=color_to_float(color_components['alpha']),
                                     R8=color_to_8_bit(color_components['red']),
                                     G8=color_to_8_bit(color_components['green']),
                                     B8=color_to_8_bit(color_components['blue']),
                                     A8=color_to_8_bit(color_components['alpha']),
                                     RH=color_to_bit_h(color_components['red']),
                                     GH=color_to_bit_h(color_components['green']),
                                     BH=color_to_bit_h(color_components['blue']),
                                     AH=color_to_bit_h(color_components['alpha']))
                break
    return sync_result_str

def color_to_float(value):
    if '.' in value:
        return value
    elif 'X' in value or 'x' in value:
        return '{:0.3f}'.format(float(int(value[-2:], 16)) / 255)
    else:
        return '{:0.3f}'.format(float(value) / 255)

def color_to_8_bit(value):
    if '.' in value:
        return '{: <5}'.format(int(float(value) * 255))
    elif 'X' in value or 'x' in value:
        return '{: <5}'.format(int(value, 16))
    else:
        return '{: <5}'.format(value)

def color_to_bit_h(value):
    if '.' in value:
        return '{: <5X}'.format(int(float(value) * 255))
    elif 'X' in value or 'x' in value:
        return '{: <5}'.format(value[-2:])
    else:
        return '{: <5X}'.format(int(value))

if __name__ == '__main__':
    project_path = sys.argv[1]
    project_name = sys.argv[2]
    os.chdir(project_path)
    system_color_names = ['black', 'darkGray', 'lightGray', 'white', 'gray', 'red', 'green', 'blue', 'cyan', 'yellow', 'magenta', 'orange', 'purple', 'brown', 'clear']
    color_file_name = 'Colors.swift'
    color_file_path = os.path.join(project_path, color_file_name)
    temp_file_name = 'Colors_temp.swift'
    temp_file_path = os.path.join(project_path, temp_file_name)
    start_tag = '//start sync tag'
    end_tag = '//end sync tag'
    sync_color_file()
    exit(0)

圖片同步腳本

import sys
import os
import json

project_path = sys.argv[1]
project_name = sys.argv[2]
os.chdir(project_path)
image_file_name = 'Images.swift'
image_file_path = os.path.join(project_path, image_file_name)
temp_file_name = 'Images_temp.swift'
temp_file_path = os.path.join(project_path, temp_file_name)
start_tag = '//start sync tag'
end_tag = '//end sync tag'
temp_file = None
if os.path.exists(image_file_path):
    os.rename(image_file_name, temp_file_name)
    temp_file = open(temp_file_path, 'r')
    image_file = open(image_file_path, "w+")
    while True:
        line = temp_file.readline()
        image_file.write(line)
        if start_tag in line:
            break
else:
    image_file = open(image_file_path, "w+")
    image_file.write('//\
                \n//  {}\
                \n//  {}\
                \n//\
                \n//  Created by XXXX on 9999/99/99.\
                \n//\
                \n\
                \nimport UIKit\
                \n\
                \nextension UIImage {{\
                \n{}\n'.format(image_file_name, project_name, start_tag))
print('current project path: {}'.format(os.getcwd()))
for folder, subFolders, files in os.walk("Assets.xcassets"):
    image_name = os.path.basename(folder)
    image_suffix = '.imageset'
    if not image_name.endswith(image_suffix):
        continue
    param_name = image_name.replace(image_suffix, '')
    image_file.write('\n\tpublic static var {0}: UIImage? {{\
        \n\t\t_ = #imageLiteral(resourceName: "{0}")\
        \n\t\treturn UIImage(named: "{0}")\
        \n\t}}\n'.format(param_name))
start_write_tail = False
if temp_file:
    while True:
        line = temp_file.readline()
        if end_tag in line:
            start_write_tail = True
        if start_write_tail:
            image_file.write(line)
        if line == '':
            break
    if not start_write_tail:
        image_file.write('\n{}\n}}'.format(end_tag))
    temp_file.close()
    os.remove(temp_file_path)
else:
    image_file.write('\n{}\n}}'.format(end_tag))
image_file.close()
exit(0)

將腳本放到py為后綴的文件中就可以了(示例中用的是color.py和image.py)妨马,
然后在Xcode的Run Script里面寫入

python3 path/for/script/image.py ${SRCROOT}/${TARGET_NAME} ${PROJECT_NAME}
python3 path/for/script/image.py ${SRCROOT}/${TARGET_NAME} ${PROJECT_NAME} 

直接在shell腳本中調(diào)用python腳本挺举,將腳本路徑換成自己的存放路徑,建議在放在項(xiàng)目根目錄下 color.py烘跺,這樣所有人都可以使用湘纵。

這樣,每次在編譯之前都會(huì)進(jìn)行一次同步滤淳,不需要手動(dòng)去維護(hù)這些硬編碼了梧喷,在編碼時(shí)也會(huì)有相應(yīng)的提示。

資源的管理也會(huì)變得簡單娇钱,刪除后管理類也會(huì)同時(shí)刪除伤柄,還能有編譯錯(cuò)誤來提示刪除的資源對代碼的影響

可以使用 literal 對資源的代碼可視化,在代碼中就可以看到顏色效果文搂,和圖片的縮略圖适刀,如上面的截圖,color_code.png和image_code.png

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末煤蹭,一起剝皮案震驚了整個(gè)濱河市笔喉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌硝皂,老刑警劉巖常挚,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異稽物,居然都是意外死亡奄毡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門贝或,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吼过,“玉大人,你說我怎么就攤上這事咪奖〉脸溃” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵羊赵,是天一觀的道長趟佃。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么闲昭? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任罐寨,我火速辦了婚禮,結(jié)果婚禮上汤纸,老公的妹妹穿的比我還像新娘衩茸。我一直安慰自己,他們只是感情好贮泞,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布楞慈。 她就那樣靜靜地躺著,像睡著了一般啃擦。 火紅的嫁衣襯著肌膚如雪囊蓝。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天令蛉,我揣著相機(jī)與錄音聚霜,去河邊找鬼。 笑死珠叔,一個(gè)胖子當(dāng)著我的面吹牛蝎宇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播祷安,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼姥芥,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了汇鞭?” 一聲冷哼從身側(cè)響起凉唐,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎霍骄,沒想到半個(gè)月后台囱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡读整,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年簿训,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片米间。...
    茶點(diǎn)故事閱讀 38,117評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡煎楣,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出车伞,到底是詐尸還是另有隱情,我是刑警寧澤喻喳,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布另玖,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏谦去。R本人自食惡果不足惜慷丽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鳄哭。 院中可真熱鬧要糊,春花似錦、人聲如沸妆丘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽勺拣。三九已至奶赠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間药有,已是汗流浹背毅戈。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留愤惰,地道東北人苇经。 一個(gè)月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像宦言,于是被迫代替她去往敵國和親扇单。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容