在Xcode中使用Asset Catalogs大致效果如下圖
代碼調(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
}
代碼效果
圖片管理類
import UIKit
extension UIImage {
//start sync tag
public static var folder: UIImage? {
_ = #imageLiteral(resourceName: "folder")
return UIImage(named: "folder")
}
//end sync tag
}
圖片效果
資源的使用就不會(huì)出現(xiàn)硬編碼了
let color = UIColor.asdw
let image = UIImage.folder
但是還是需要我們手動(dòng)去維護(hù)這些個(gè)管理類旅薄,也是一件比較麻煩的事。
我們可以使用Xcode的Run Script來幫助我門來完成這個(gè)管理類的維護(hù)工作,這樣就能幫助我們省去很多的工作量
我們可以使用腳本來幫助我們完成管理類與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