在ios项目开发过程中根据设计图绘制ui时,往往给咱们的是16进制颜色色值,比如:#FFFFFF、#000000、0xFFFFFFF等等,然而UIColor原生方法中并没有能直接使用这些的方法,故而对UIColor进行扩展,添加些实用方法
extension UIColor {
/// 通过哈希值获取颜色
class func hexColor(_ hexColor:Int, alpha:CGFloat = 1) ->UIColor {
let red = CGFloat((hexColor & 0xFF0000) >> 16)/255.0
let green = CGFloat((hexColor & 0xFF00) >> 8)/255.0
let blue = CGFloat(hexColor & 0xFF)/255.0
return UIColor(red: red, green: green, blue: blue, alpha: alpha)
}
}
"#FFFFFF,%25"中"%25"为透明度,若未设置,则默认为1
extension UIColor {
/// 通过哈希值获取颜色
class func zj_hexColor(_ hexColor:String) ->UIColor {
let resultArray = hexColor.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines).uppercased().components(separatedBy: ",")
if var cString = resultArray.first {
// Remove the prefix
if cString.hasPrefix("0X") {
let start = cString.index(cString.startIndex, offsetBy: 2)
cString = String(cString[start..<cString.endIndex])
}
if cString.hasPrefix("#") {
let start = cString.index(cString.startIndex, offsetBy: 1)
cString = String(cString[start..<cString.endIndex])
}
guard cString.count == 6 else {
return .black
}
var redStr:String = ""
var greenStr:String = ""
var blueStr:String = ""
for i in 0...2 {
let start = cString.index(cString.startIndex, offsetBy: i * 2)
let end = cString.index(start, offsetBy: 2)
if i == 0 {
redStr = String(cString[start..<end])
}else if i == 1 {
greenStr = String(cString[start..<end])
}else{
blueStr = String(cString[start..<end])
}
}
var r:UInt64 = 0
Scanner(string: redStr).scanHexInt64(&r)
var g:UInt64 = 0
Scanner(string: greenStr).scanHexInt64(&g)
var b:UInt64 = 0
Scanner(string: blueStr).scanHexInt64(&b)
var alpha:CGFloat = 1
if resultArray.count > 1{
let alphaString = resultArray[1]
.replacingOccurrences(of: " ", with: "", options: .literal, range: nil)
.replacingOccurrences(of: "%", with: "", options: .literal, range: nil)
if let a = Float(alphaString) {
if resultArray[1].contains("%") {
alpha = CGFloat(a/100.0)
}else{
alpha = CGFloat(a)
}
}
}
return UIColor(red: CGFloat(r)/255.0, green: CGFloat(g)/255.0, blue: CGFloat(b)/255.0, alpha: alpha)
}else{
return UIColor.clear
}
}
}
通过上面的两个方法,基本就可以满足项目中的颜色设置需求。
第一种:在每个页面上,每个需要变化的ui都根据浅色/深色模式赋予对应值。
class HZJController: UIViewController {
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
if let previous = previousTraitCollection {
self.changeUI(previous.userInterfaceStyle)
}
}
/// 修改控件样式等
/// - Parameter style: <#style description#>
func changeUI(_ style:UIUserInterfaceStyle){
switch style {
case .unspecified:
self.view.backgroundColor = .white
case .light:
self.view.backgroundColor = .black
case .dark:
self.view.backgroundColor = .zj_hexColor("#FF0000,%50")
@unknown default:
break
}
}
}
不过这样确实太麻烦了,如果涉及到界面布局变化的话,可以考虑这么做,但是若只有颜色的改变,就不建议这么做了
第二种:还是需要对颜色进行处理,这里就要使用到系统自带的这个方法了
public init(dynamicProvider: @escaping (UITraitCollection) -> UIColor)
extension UIColor {
/// 颜色翻转
/// - Returns: <#description#>
func invertColor() ->UIColor {
var r:CGFloat = 0
var g:CGFloat = 0
var b:CGFloat = 0
self.getRed(&r, green: &g, blue: &b, alpha: nil)
return UIColor(red: 1-r, green: 1-g, blue: 1-b, alpha: 1)
}
/// 获取随系统变化的颜色
/// - Parameters:
/// - light: 白天模式的颜色
/// - dark: 暗黑模式的颜色
/// - invertColor: 是否翻转颜色:仅当dark==nil时有效,若true,则使用light的翻转颜色
/// - Returns: <#description#>
static func getAutoColor(_ light:String,_ dark:String? = nil ,_ invertColor:Bool = false)->UIColor{
let lightColor = UIColor.zj_hexColor(light)
let darkColor = dark != nil ? UIColor.zj_hexColor(dark!) : invertColor ? lightColor.invertColor() : lightColor
if #available(iOS 13.0, *) {
return UIColor.init { (traitCollection) -> UIColor in
switch traitCollection.userInterfaceStyle {
case .dark:
return darkColor
default:
return lightColor
}
}
} else {
return lightColor
}
}
}
如此,我们就可以定义颜色
extension UIColor {
static let zj_0 = UIColor.getAutoColor("#000000", nil)
static let zj_1 = UIColor.getAutoColor("#000000", "#ffffff", false)
static let zj_2 = UIColor.getAutoColor("#000000", nil, true)
static let zj_3 = UIColor.getAutoColor("#000000", "#123456", true)
}
其中zj_0只会显示为000000;
我们知道#000000进行16位反转后是#ffffff,故而zj_1和zj_2是一个效果,他们会在浅色模式下显示000000,在深色模式时显示ffffff;
而zj_3会在浅色模式下显示000000,在深色模式时显示123456;
注意:颜色的显示时根据当前window的UIUserInterfaceStyle变化的
由于我使用的SceneDelegate,故而在SceneDelegate中对window进行设置:
随系统变化:
self.window?.overrideUserInterfaceStyle = .unspecified
只要浅色:
self.window?.overrideUserInterfaceStyle = .light
只要深色:
self.window?.overrideUserInterfaceStyle = .dark