【问题标题】:Use Hex color in SwiftUI在 SwiftUI 中使用十六进制颜色
【发布时间】:2019-11-14 09:08:06
【问题描述】:

在 UIKit 中,我们可以使用扩展来为几乎所有东西设置十六进制颜色。 https://www.hackingwithswift.com/example-code/uicolor/how-to-convert-a-hex-color-to-a-uicolor

但是当我尝试在 SwiftUI 上执行此操作时,这是不可能的,看起来 SwiftUI 没有将 UIColor 作为参数。

    Text(text)
        .color(UIColor.init(hex: "FFF"))

错误信息:

Cannot convert value of type 'UIColor' to expected argument type 'Color?'

我什至尝试为Color 扩展,而不是UIColor,但我没有任何运气

我的颜色扩展:

导入 SwiftUI

extension Color {
    init(hex: String) {
        let scanner = Scanner(string: hex)
        scanner.scanLocation = 0
        var rgbValue: UInt64 = 0
        scanner.scanHexInt64(&rgbValue)

        let r = (rgbValue & 0xff0000) >> 16
        let g = (rgbValue & 0xff00) >> 8
        let b = rgbValue & 0xff

        self.init(
            red: CGFloat(r) / 0xff,
            green: CGFloat(g) / 0xff,
            blue: CGFloat(b) / 0xff, alpha: 1
        )
    }
}

错误信息:

Incorrect argument labels in call (have 'red:green:blue:alpha:', expected '_:red:green:blue:opacity:')

【问题讨论】:

  • 初始化是这个:developer.apple.com/documentation/swiftui/color/3265484-init 它缺少一个参数,正如您在错误消息中看到的那样:'red:green:blue:alpha:' vs '_:red:green:blue:opacity:,请参阅开头的_:对于_ colorSpace:opacityalpha
  • @Larme 是的,我试过了,它修复了编译错误,但没有任何结果,它没有为视图设置颜色,你自己解决了吗?如果你这样做,请添加代码。

标签: ios uicolor swiftui


【解决方案1】:

你快到了,你使用了错误的初始化参数:

extension Color {
    init(hex: String) {
        let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
        var int: UInt64 = 0
        Scanner(string: hex).scanHexInt64(&int)
        let a, r, g, b: UInt64
        switch hex.count {
        case 3: // RGB (12-bit)
            (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
        case 6: // RGB (24-bit)
            (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF)
        case 8: // ARGB (32-bit)
            (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
        default:
            (a, r, g, b) = (1, 1, 1, 0)
        }

        self.init(
            .sRGB,
            red: Double(r) / 255,
            green: Double(g) / 255,
            blue:  Double(b) / 255,
            opacity: Double(a) / 255
        )
    }
}

【讨论】:

  • 它解决了编译错误,谢谢,但它没有在SwiftUI中设置视图的颜色,没有错误但没有结果
  • 我尝试了 Color("ff00ff") 并且工作正常。你传递的十六进制是什么?
  • 还请说明您获得的特定十六进制参数的颜色。
  • 您的解决方案不适用于“#hexColorStr”。请使用我的:stackoverflow.com/questions/36341358/…
  • 这失败了:XCTAssertEqual(Color(hex: "0xFFFFFF"), Color(red: 255, green: 255, blue: 255))。连同“ffffff”和“FFFFFF”
【解决方案2】:

下面的另一个替代方法是使用 Int 表示十六进制,但当然,如果您愿意,可以将其更改为 String。

extension Color {
    init(hex: UInt, alpha: Double = 1) {
        self.init(
            .sRGB,
            red: Double((hex >> 16) & 0xff) / 255,
            green: Double((hex >> 08) & 0xff) / 255,
            blue: Double((hex >> 00) & 0xff) / 255,
            opacity: alpha
        )
    }
}

用法示例:

Color(hex: 0x000000)
Color(hex: 0x000000, alpha: 0.2)

【讨论】:

  • 这是一个很好的实现!你将如何使用 String 而不是 Int?
  • 对于任何感兴趣的人,在《Swift 编程语言》一书中Advanced Operators 中解释了这种方法(在与 SwiftUI 无关的一般上下文中)。整章都值得一读。提示:理解的关键是右移和按位与,最简单的例子是 1. 使用右移 (number >> 1) 将数字减半和 2. 检查数字是否为奇数 (number & 0x1 == 1)。 Bitwise_operation 维基百科的文章也值得一读。
  • 为什么你创建一个元组只是为了在下一个语句中提取它的所有值?这没有意义。
  • @PeterSchorn 是有道理的,我删除了元组。谢谢!
  • @TolgahanArıkan 没问题。很高兴我能帮上忙。
【解决方案3】:

这是我的解决方案的游乐场。它在回退之后添加回退,并且仅依赖 hexString 的颜色和 alpha。

import SwiftUI

extension Color {
    init(hex string: String) {
        var string: String = string.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
        if string.hasPrefix("#") {
            _ = string.removeFirst()
        }

        // Double the last value if incomplete hex
        if !string.count.isMultiple(of: 2), let last = string.last {
            string.append(last)
        }

        // Fix invalid values
        if string.count > 8 {
            string = String(string.prefix(8))
        }

        // Scanner creation
        let scanner = Scanner(string: string)

        var color: UInt64 = 0
        scanner.scanHexInt64(&color)

        if string.count == 2 {
            let mask = 0xFF

            let g = Int(color) & mask

            let gray = Double(g) / 255.0

            self.init(.sRGB, red: gray, green: gray, blue: gray, opacity: 1)

        } else if string.count == 4 {
            let mask = 0x00FF

            let g = Int(color >> 8) & mask
            let a = Int(color) & mask

            let gray = Double(g) / 255.0
            let alpha = Double(a) / 255.0

            self.init(.sRGB, red: gray, green: gray, blue: gray, opacity: alpha)

        } else if string.count == 6 {
            let mask = 0x0000FF
            let r = Int(color >> 16) & mask
            let g = Int(color >> 8) & mask
            let b = Int(color) & mask

            let red = Double(r) / 255.0
            let green = Double(g) / 255.0
            let blue = Double(b) / 255.0

            self.init(.sRGB, red: red, green: green, blue: blue, opacity: 1)

        } else if string.count == 8 {
            let mask = 0x000000FF
            let r = Int(color >> 24) & mask
            let g = Int(color >> 16) & mask
            let b = Int(color >> 8) & mask
            let a = Int(color) & mask

            let red = Double(r) / 255.0
            let green = Double(g) / 255.0
            let blue = Double(b) / 255.0
            let alpha = Double(a) / 255.0

            self.init(.sRGB, red: red, green: green, blue: blue, opacity: alpha)

        } else {
            self.init(.sRGB, red: 1, green: 1, blue: 1, opacity: 1)
        }
    }
}

let gray0 = Color(hex: "3f")
let gray1 = Color(hex: "#69")
let gray2 = Color(hex: "#6911")
let gray3 = Color(hex: "fff")
let red = Color(hex: "#FF000044s")
let green = Color(hex: "#00FF00")
let blue0 = Color(hex: "0000FF")
let blue1 = Color(hex: "0000F")

为了从 Color 中获取 hexString.. 好吧,这不是一个公共 API。 我们仍然需要依赖 UIColor 实现。

PS:我看到了下面的组件解决方案..但是如果将来API发生变化,我的版本会更稳定一些。

【讨论】:

  • 这是最好的答案。如果您将不透明度添加为参数,它将是最完整的。
  • 同意,我尝试了许多解决方案,这是最好的答案。我不知道为什么它没有得到更多的支持。道具@Stefan!至于不透明度,只需像在 SwiftUI 中通常那样链接它... Color(hex: "#003366").opacity(0.2)
【解决方案4】:

试试这个

extension Color {
init(hex: Int, opacity: Double = 1.0) {
    let red = Double((hex & 0xff0000) >> 16) / 255.0
    let green = Double((hex & 0xff00) >> 8) / 255.0
    let blue = Double((hex & 0xff) >> 0) / 255.0
    self.init(.sRGB, red: red, green: green, blue: blue, opacity: opacity)
}
}

使用

Text("Hello World!")
            .background(Color(hex: 0xf5bc53))

Text("Hello World!")
            .background(Color(hex: 0xf5bc53, opacity: 0.8))

【讨论】:

  • 我喜欢这个解决方案,简单、简洁、优雅
  • 但是编译速度很慢 :) 从头开始​​ 9 秒 :)
【解决方案5】:

用法
UIColor.init(hex: "f2000000")
UIColor.init(hex: "#f2000000")
UIColor.init(hex: "000000")
UIColor.init(hex: "#000000")

extension UIColor {
public convenience init(hex:String) {
var cString:String = hex.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()
    
    if (cString.hasPrefix("#")) {
        cString.remove(at: cString.startIndex)
    }
    var r: CGFloat = 0.0
    var g: CGFloat = 0.0
    var b: CGFloat = 0.0
    var a: CGFloat = 1.0
    
    var rgbValue:UInt64 = 0
    Scanner(string: cString).scanHexInt64(&rgbValue)
    
    if ((cString.count) == 8) {
        r = CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0
        g =  CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0
        b = CGFloat((rgbValue & 0x0000FF)) / 255.0
        a = CGFloat((rgbValue & 0xFF000000)  >> 24) / 255.0
        
    }else if ((cString.count) == 6){
        r = CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0
        g =  CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0
        b = CGFloat((rgbValue & 0x0000FF)) / 255.0
        a =  CGFloat(1.0)
    }
    
    
    self.init(  red: r,
                green: g,
                blue: b,
                alpha: a
    )
} }

【讨论】:

  • 您使用的是 UIKit 对象:UIColor,而不是 SwiftUI Color。
【解决方案6】:

从十六进制(3、4、6、8 个字符)创建 SwiftUI 颜色,支持 #alphaweb constantsUIColor constants。用法示例如下。

Swift Package iOS 14+ 包括对 Color 十六进制、随机、CSS 颜色和 UserDefaults 的支持。

【讨论】:

  • 我在文档和代码完成中都没有看到Color(hex:
  • @ScottyBlades 抱歉。如果您使用的是 iOS 14,这里有一个包,它将为十六进制和 UserDefaults 提供颜色支持。 github.com/nbasham/BlackLabsSwiftUIColor
【解决方案7】:

我还通过 hackingwithswift 使用了UIColor 的解决方案。 这是Color的改编版:

init?(hex: String) {
    var hexSanitized = hex.trimmingCharacters(in: .whitespacesAndNewlines)
    hexSanitized = hexSanitized.replacingOccurrences(of: "#", with: "")

    var rgb: UInt64 = 0

    var red: Double = 0.0
    var green: Double = 0.0
    var blue: Double = 0.0
    var opacity: Double = 1.0

    let length = hexSanitized.count

    guard Scanner(string: hexSanitized).scanHexInt64(&rgb) else { return nil }

    if length == 6 {
        red = Double((rgb & 0xFF0000) >> 16) / 255.0
        green = Double((rgb & 0x00FF00) >> 8) / 255.0
        blue = Double(rgb & 0x0000FF) / 255.0

    } else if length == 8 {
        red = Double((rgb & 0xFF000000) >> 24) / 255.0
        green = Double((rgb & 0x00FF0000) >> 16) / 255.0
        blue = Double((rgb & 0x0000FF00) >> 8) / 255.0
        opacity = Double(rgb & 0x000000FF) / 255.0

    } else {
        return nil
    }

    self.init(.sRGB, red: red, green: green, blue: blue, opacity: opacity)
}

【讨论】:

    猜你喜欢
    • 2021-10-07
    • 2021-02-17
    • 1970-01-01
    • 2014-07-03
    • 2020-03-05
    • 2019-06-16
    • 2021-03-08
    • 2019-10-29
    • 2018-02-03
    相关资源
    最近更新 更多