在UI开发中,颜色是一个非常重要的功能。SwiftUI中内置了强大的颜色处理解决方案,包括Color、UIColor、CGColor等颜色类型,以及AngularGradient、LinearGradient、RadialGradient等渐变颜色视图。
一、Color 颜色
Color是SwiftUI内置的一个定义上下文颜色的数据类型,包含了常用的标准颜色,如黑色(black)、蓝色(blue)、棕色(brown)、青色(cyan)、灰色(gray)、绿色(green)、靛蓝色(indigo)、薄荷色(mint)、橙色(orange)、粉色(pink)、紫色(purple)、红色(red)、青色(teal)、白色(white)和黄色(yellow)等,以及清除颜色(透明)。
1. Color视图
由于Color符合View协议,我们可以直接将其作为视图使用,以定义的颜色显示为矩形视图并布满可用的区域。例如:
```swift
Color("background") // 使用Assets.xcassets里定义的颜色
Color.green // 内置颜色:绿色
Color(hue: 0.3, saturation: 0.4, brightness: 0.5, opacity: 0.6) // 根据色调、饱和度和亮度值创建恒定颜色。
Color(hue: 0.3, saturation: 0.4, brightness: 0.5) // 同上,但不使用透明度
Color(.sRGB, white: 0.9, opacity: 0.8) // 恒定的灰度颜色。
Color(red: 0.1, green: 0.2, blue: 0.3) // 通过reb值创建颜色
Color(red: 1, green: 0, blue: 0.2) // 通过reb值创建红色
Color(red: 255/255.0, green: 0/255.0, blue: 51/255.0,opacity: 1) // 颜色与上相同,255/255.0 前面的255参数取值于photoshop
```
2. 扩展Color让其可调用hex颜色值
如果上述颜色API不能满足需求,我们还可以直接使用hex颜色值来处理。通过扩展Color,我们可以将16进制转换为RGB值并支持alpha通道。例如:
```swift
Color("#FFAABB") // 通过十六进制颜色值创建颜色
```
```swift
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
)
}
}
//使用hex值设置颜色:
Color(hex: 0x000000)//黑色
Color(hex: 0x000000, alpha: 0.2)//淡灰色
//需要将网页里的#000000前面的#修改为0x即可。当然可以对扩展写更多的代码以达到支持以#开始的hex值。
//从UIColor或NSColor颜色创建颜色。
//基本上内置的颜色初始化就能满足我们开发中的需要,但有时候我们从UIKit转swiftUI的时候需要对原来的uiColor直接使用:
#if os(iOS)
Color(uiColor: .link)//iOS 15+ 可用
#elseif os(macOS)
Color(nsColor: .linkColor)//macOS 12.0+可用
#endif
//从cgColor创建颜色。
Color(cgColor: CGColor(red: 0, green: 0, blue: 0, alpha: 0.1))//黑色的0.1透明:谈灰
//颜色判断。因为颜色是符合Equatable协议的,所以我们可以使用==判断颜色。
if(Color.black == Color(red: 0, green: 0, blue: 0)) {
print("颜色一样")
}
//应用颜色。可以通过 .foregroundColor、.fill、.background、.overlay等修改器应用颜色。
```
在SwiftUI中,我们可以使用Text()视图来展示文本。要设置一个具有特定样式的文本,我们可以使用`.padding()`、`.foregroundColor()`、`.background()`等修饰符。例如:
```swift
Text("网络人 55mx.com")
.padding()
.foregroundColor(.red)
.opacity(0.8)
.background(Capsule().fill(.yellow))
.overlay(.clear)
```
这段代码创建了一个带有红色前景色、黄色背景和白色边距的文本。其中,`.padding()`用于设置边距,`.foregroundColor(.red)`设置前景色为红色,`.background(Capsule().fill(.yellow))`设置背景色为黄色,`.overlay(.clear)`用于清除文本周围的遮罩。
以下是重构后的代码:
```swift
// 创建灰度值,白度为0%(0.0)时为黑色,白度为100%(1.0)时为纯白色
init(white: CGFloat, alpha: CGFloat) {
self.red = white
self.green = white
self.blue = white
self.alpha = alpha
}
// 基于RGB的另一种表示方式
init(hue: CGFloat, saturation: CGFloat, brightness: CGFloat, alpha: CGFloat) {
let color = UIColor(hue: hue, saturation: saturation, brightness: brightness, alpha: alpha)
let red = color.red
let green = color.green
let blue = color.blue
self.red = red
self.green = green
self.blue = blue
self.alpha = alpha
}
// RGB+通道
init(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
self.red = red
self.green = green
self.blue = blue
self.alpha = alpha
}
// RGB的另一种用法
init(displayP3Red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
r := displayP3Red * MAX_VALUE
g := displayP3Green * MAX_VALUE
b := displayP3Blue * MAX_VALUE
r = round(r)
g = round(g)
b = round(b)
init(red: r, green: g, blue: b, alpha: max(0, min(MAX_VALUE, a))) // clamping the value between [0, MAX_VALUE] and [0, MAX_VALUE] for uicolor components.
}
//使用CGColor核心图形颜色
init(cgColor: CGColor) {
r := UInt8((cgColor.colorComponents!.r * MAX_VALUE + MIN_VALUE) >> SHIFT_RED) // clamping the value between [MIN_VALUE, MAX_VALUE] and [0, MAX_VALUE] for uicolor components.
g := UInt8((cgColor.colorComponents!.g * MAX_VALUE + MIN_VALUE) >> SHIFT_GREEN) // clamping the value between [MIN_VALUE, MAX_VALUE] and [0, MAX_VALUE] for uicolor components.
b := UInt8((cgColor.colorComponents!.b * MAX_VALUE + MIN_VALUE) >> SHIFT_BLUE) // clamping the value between [MIN_VALUE, MAX_VALUE] and [0, MAX_VALUE] for uicolor components.
init(red: r, green: g, blue: b, alpha: max(0, min(MAX_VALUE, CGFloat(cgColor.alpha)))) // clamping the value between [0, MAX_VALUE] and [0, MAX_VALUE] for uicolor components.
}
//使用来源于UIImage的图片颜色
init(patternImage image: UIImage?) where T == Self, T.Element == (UInt8, UInt8, UInt8)?, T.Element? >= (nil, nil, nil) && T.Element? <= (maxUInt8Value, maxUInt8Value, maxUInt8Value), T == Array
//使用ciColor颜色
init(ciColor: CIColor) {
r := Double((ciColor.redComponent * Double(MAX_VALUE)) + DOUBLE(MIN_VALUE)) // clamping the value between [MIN_VALUE, MAX_VALUE] and [0, MAX_VALUE] for uicolor components.
g := Double((ciColor.greenComponent * Double(MAX_VALUE)) + DOUBLE(MIN_VALUE)) // clamping the value between [MIN_VALUE, MAX_VALUE] and [0, MAX_VALUE] for uicolor components.
b := Double((ciColor.blueComponent * Double(MAX_VALUE)) + DOUBLE(MIN_VALUE)) // clamping the value between [MIN_VALUE, MAX_VALUE] and [0, MAX_VALUE] for uicolor components.
init(red: Float(r), green: Float(g), blue: Float(b), alpha: Float(ciColor.alphaComponent * Double(MAX_VALUE)) + DOUBLE(MIN_VALUE)) // clamping the value between [MIN_VALUE, MAX_VALUE] and [0, MAX_VALUE] for uicolor components./255*100%=497631f;/255*1f=1f;/255*1f=1f;/255*1f=1f;[-999999999999999999999999999];let's get outta here" /> // clamping the value between [MIN_VALUE, MAX_VALUE] and [0, MAX_VALUE] for uicolor components.
//******** 固定颜色 ************
let black = UIColor.black //黑色
let darkGray = UIColor.darkGray //深灰
let lightGray = UIColor.lightGray //浅灰
let white = UIColor.white //白色
let gray = UIColor.gray //灰色
let red = UIColor.red //红色
let green = UIColor.green //绿色
let blue = UIColor.blue //蓝色
let cyan = UIColor.cyan //蓝绿色
let yellow = UIColor.yellow //黄色
let magenta = UIColor.magenta //紫红色
let orange = UIColor.orange //橘黄色
let purple = UIColor.purple //紫色
let brown = UIColor.brown //褐色
let clear = UIColor.clear //透明色
//******** 自适应颜色 ************
let systemBlue = UIColor.systemBlue //系统蓝色
let systemBrown = UIColor.systemBrown //系统棕色
let systemGreen = UIColor.systemGreen //系统绿色
let systemIndigo = UIColor.systemIndigo //系统靛蓝色
let systemOrange = UIColor.systemOrange //系统橙色
let systemPink = UIColor.systemPink //系统粉红色
let systemPurple = UIColor.systemPurple //系统紫色
let systemRed = UIColor.systemRed //系统红色
let systemTeal = UIColor.systemTeal //系统青色
let systemYellow = UIColor.systemYellow //系统黄色
//******** 适应性强的灰色 ***********
let systemGray = UIColor.systemGray //标准基灰色
let systemGray2 = UIColor.systemGray2 //二级灰色阴影
let systemGray3 = UIColor.systemGray3 //三级灰色阴影
let systemGray4 = UIColor.systemGray4 //四级灰色阴影
let systemGray5 = UIColor.systemGray5 //五级灰色阴影
let systemGray6 = UIColor.systemGray6 //六级灰色阴影
//******** 标签颜色 ***********
let label = UIColor.label //文本标签的颜色。
let secondaryLabel = UIColor.secondaryLabel //次要内容的文本标签的颜色。
let tertiaryLabel = UIColor.tertiaryLabel //三级内容的文本标签的颜色。
let quaternaryLabel = UIColor.quaternaryLabel //四元内容的文本标签的颜色。
//******** 填充颜色 ***********
let systemFill = UIColor.systemFill //薄和小形状的覆盖填充颜色。
let secondarySystemFill = UIColor.secondarySystemFill //中等大小形状的叠加填充颜色。
let tertiarySystemFill = UIColor.tertiarySystemFill //大型形状的叠加填充颜色。
let quaternarySystemFill = UIColor.quaternarySystemFill //包含复杂内容的大区域的叠加填充颜色。
//******** 背景颜色 ***********
let systemBackground = UIColor.systemBackground //界面主背景的颜色。
let secondarySystemBackground = UIColor.secondarySystemBackground //分层在主背景之上的内容颜色。
let tertiarySystemBackground = UIColor.tertiarySystemBackground //分层在次要背景之上的内容的颜色。
let systemGroupedBackground = UIColor.systemGroupedBackground //分组界面的主背景颜色。
let secondarySystemGroupedBackground = UIColor.secondarySystemGroupedBackground //分层在分组界面主背景之上的内容颜色。
let tertiarySystemGroupedBackground = UIView().traitCollection.userInterfaceStyle == .dark ? secondarySystemGroupedBackground:tertiarySystemGroupedBackground;//次要背景之上的内容颜色。
```
三、CGColor
以CG开头的都是系统核心图形参数(Core Graphic),其中CGColor是系统中的基本颜色表示,类似于CGPoint、CGFloat和CGSize等。虽然它的API不多,但我们主要使用color.cgColor的Color变量将Color转换为CGColor。需要注意的是,这是一个可选类型(optional),不能保证100%成功转换。
CGColor可以转换为UIColor,然后再转换回Color。因此,它们之间可以通过直接或间接的方法进行转换。
四、渐变颜色
在SwiftUI中,有一种内置方法可以将渐变颜色应用于其视图。共有三种类型的渐变:线性渐变、径向渐变和角度渐变。
在我们访问每个渐变之前,让我们从它们的共同组件Gradient开始了解。Gradient是一个结构体,它包含用于渲染所有类型的渐变的信息,该渐变表示为一个色标数组。Gradient.Stop是一个结构体,表示渐变中的每种颜色和位置(范围为0到1)。
你可以通过以下方式初始化Gradient.Stop:
```swift
Gradient(stops: [.init(color: .black, location: 0), .init(color: .pink, location: 0.5)])
```
如果您希望所有**Gradient.Stop**的位置均等分布,也可以使用Color对其进行初始化。例如:
```swift
Gradient(colors: [.black, .pink]) // 结果相同
Gradient(stops: [.init(color: .black, location: 0), .init(color: .pink, location: 1)])
```
它可以包含两个以上的停靠点。例如:
```swift
Gradient(colors: [.black, .pink, .black])
```
以下是初始化Gradient的不同方法的示例。
## AngularGradient 角梯度渐变
AngularGradient(gradient: gradient, center: .center)
上述代码是最简单的 AngularGradient 初始化形式。在这种情况下,我们定义了一个圆的中心,然后从 0 度开始绘制颜色,顺时针方向直到完成整个圆形。
AngularGradient(gradient: gradient, center: .center, angle: .degrees(90))
如果我们不想从 0 度开始,可以通过将 angle 参数设置为所需的起始角度来指定起始角度。在上述示例中,我们将起始角度设置为 90 度。这将在指定的中心点处创建一个逆时针方向的渐变。
AngularGradient(gradient: gradient, center: .center, startAngle: .degrees(90), endAngle: .degrees(180))
要指定终止角,我们需要使用 endAngle 参数。在上述示例中,我们将终止角度设置为 180 度。这意味着渐变将从 90 度开始并在终止角度处停止绘制颜色。
通过一个视图详解:
假设我们有一个圆形视图,并且希望在其中应用一种颜色渐变。首先,我们需要定义渐变的颜色和位置。我们可以使用 `Gradient` 类或 `AngularGradient` 类来实现这一点。例如:
```swift
let gradient = Gradient(colors: [.black, .pink])
let angularGradient = AngularGradient(gradient: gradient, center: .center)
```
接下来,我们需要将渐变应用于视图。这可以通过将渐变作为图像层添加到视图上来实现。例如:
```swift
let layer = CALayer()
layer.contents = gradientImageFromGradient(angularGradient).cgImage!
view.layer.addSublayer(layer)
```
在这个例子中,我们使用 `gradientImageFromGradient` 函数将渐变转换为图像格式,并将其分配给图像层的内容属性。最后,我们将图像层添加到视图的图层上,以便在视图上显示渐变效果。
```swift
import SwiftUI
struct AngularSample: View {
let gradient: [Color] = [.red, .orange, .yellow, .green, .blue, .purple]
var body: some View {
HStack {
VStack(alignment: .center) {
Rectangle()
.fill(
AngularGradient(gradient: gradient, center: .center)
)
.frame(width: 200, height: 200)
}
VStack(alignment: .center) {
Rectangle()
.fill(
AngularGradient(gradient: gradient, center: .center, angle: .degrees(90))
)
.frame(width: 200, height: 200)
}
VStack(alignment: .center) {
Rectangle()
.fill(
AngularGradient(gradient: gradient, center: .center, startAngle: .degrees(90), endAngle: .degrees(180))
)
.frame(width: 200, height: 200)
}
}
}
}
```
AngularGradient(gradient: gradient, center: center) 是起始角和终止角形成一个完整圆的正常情况。每种颜色都会均匀分布。例如,当起始角为0度,终止角为360度时,将形成一个完整的圆。
b. 终止角 - 起始角 > 2π
这是总角度大于圆的情况。额外的角度会吃掉第一个圆圈部分。以下是角度梯度的示例。
1. 当起始角为0度,终止角为360度时,将形成一个完整的圆。
```scss
AngularGradient(gradient: gradient, center: .center, startAngle: .degrees(0), endAngle: .degrees(360))
```
2. 当起始角为0度,终止角为360 + 45度时,将形成一个圆和45度角。
```scss
AngularGradient(gradient: gradient, center: .center, startAngle: .degrees(0), endAngle: .degrees(360 + 45))
```
3. 当起始角为0度,终止角为360 + 360度时,将形成两个圆。
```scss
AngularGradient(gradient: gradient, center: .center, startAngle: .degrees(0), endAngle: .degrees(360 + 360))
```
在这种情况下,您只会看到三种颜色(绿色、蓝色、紫色),因为六种颜色渐变是在两个圆圈的总角度中呈现的,因此前三种颜色(红色、橙色、黄色)将绘制在第一个圆圈上将被第二个圆圈覆盖。这就是为什么在开始时您只能看到三种最终颜色(绿色、蓝色、紫色)和一点黄色(第一个圆圈的最后一种颜色)。
c. 终止角 - 起始角 < 2π
最后一种情况是起点和终点角度没有形成一个完整的圆。缺失的区域(开始和结束之间)将均匀地涂上渐变的第一种颜色和最后一种颜色。例如,当起始角为90度,终止角为270度时,将形成一个半圆形而不是一个完整的圆形。
// 请注意,角度可以是负值,它将逆时针旋转。AngularGradient(gradient: gradient, center: .center, startAngle: .degrees(-90), endAngle: .degrees(180)) AngularGradient(gradient: gradient, center: .center, startAngle: .degrees(0), endAngle: .degrees(90)) AngularGradient(gradient: gradient, center: .center, startAngle: .degrees(90), endAngle: .degrees(270))
所有这些梯度都是ShapeStyle和View协议,所以你可以在任何需要这两个协议的地方使用它们。我现在能想到的常见地方是一个独立的View、.background.fill和.strokea Shape。
2、LinearGradient线性梯度
这是最常见的渐变类型。这是我用来渲染上面初始化Gradient例子的那个。渐变沿轴应用颜色函数,由其起点和终点定义。渐变将单位空间点映射到每个填充渐变的形状的边界矩形中。
简而言之,您使用UnitPoint指定渐变的起点和终点,一个表示 x、y 坐标空间(范围从 0 到 1)的结构体,并且渐变停止将根据每个停止的位置沿该路径呈现。
SwiftUI已预定义UnitPoint,.zero,.center,leading,trailing,top,bottom,topLeading,topTrailing,bottomLeading,和bottomTrailing。如果您有特殊需要,您可以像普通结构一样创建自己的UnitPoint。
```swift
UnitPoint(x: 1, y: 0) // .topTrailing
```
以下是LinearGradient不同设置的示例:
以下是重构后的内容:
### 1. LinearGradient 线性梯度
LinearGradient 是一种常见的渐变类型,它通过定义起点和终点来创建一个线性的渐变效果。在 SwiftUI 中,可以使用 Gradient 类来创建 LinearGradient。
```swift
let gradient = Gradient(colors: [.black, .pink])
LinearGradient(gradient: gradient, startPoint: .leading, endPoint: .topTrailing)
LinearGradient(gradient: gradient, startPoint: .top, endPoint: .bottom)
LinearGradient(gradient: gradient, startPoint: .bottomTrailing, endPoint: .topLeading)
```
### 2. RadialGradient 径向梯度
RadialGradient 是另一种常见的渐变类型,它通过定义起点、终点和中心点来创建一个径向的渐变效果。在 SwiftUI 中,可以使用 RadialGradient 类来创建径向渐变。
```swift
RadialGradient(gradient: gradient, center: .center, startRadius: 1, endRadius: 100)
```
其中,`center` 是 UnitPoint,表示渐变的中心点;`startRadius` 和 `endRadius` 是 CGFloat 类型的值,表示以点为单位的起始半径和结束半径。
```swift
struct RadialSample: View {
let gradient = Gradient(colors: [.black, .pink])
var body: some View {
HStack {
VStack {
Rectangle()
.fill(RadialGradient(gradient: self.gradient, center: .center, startRadius: 1, endRadius: 100))
.frame(width: 200, height: 200)
Text("radius 1 to 100")
.fontWeight(.semibold)
.foregroundColor(.white)
}
VStack {
Rectangle()
.fill(RadialGradient(gradient: self.gradient, center: .center, startRadius: 1, endRadius: 100))
.frame(width: 200, height: 100)
Text("radius 1 to 100")
.fontWeight(.semibold)
.foregroundColor(.white)
}
VStack {
Rectangle()
.fill(RadialGradient(gradient: self.gradient, center: .center, startRadius: 1, endRadius: 50))
.frame(width: 200, height: 100)
Text("radius 1 to 50")
.fontWeight(.semibold)
.foregroundColor(.white)
}
}
}
}
```
五、Material背景材料
Material是一种应用于背景(.background)和覆盖(.overlay)的效果,是今年iOS 15新增的类型。尽管它不属于颜色,但与颜色并无差别。请注意,材质本身并非视图,但添加材质后,会在修改后的视图与背景之间插入半透明层。
值得注意的是,Material提供的模糊效果并非简单的不透明度。相反,它使用特定于平台的混合,产生类似于重度磨砂玻璃的效果。您可以使用复杂的背景更容易地看到这一点,例如图像:
```swift
ZStack { Image(“chili_peppers”) .resizable() .aspectRatio(contentMode: .fit) Label(“Flag”, systemImage: “flag.fill”) .padding() .background(.regularMaterial) }
```
对于物理材料,背景颜色通过的程度取决于厚度。此外,效果还会随着外观的明暗而变化。如果您需要材质具有特定形状,可以使用方法修改器。例如,您可以创建带圆角的材质:
```swift
ZStack { Color.teal Label(“Flag”, systemImage: “flag.fill”) .padding() .background(.regularMaterial, in: RoundedRectangle(cornerRadius: 8)) }
```
需要注意的是,Material会模糊应用中的背景,但不会模糊屏幕上应用背后的背景。例如,主屏幕上的内容不会影响小部件的外观。此外,添加材质时,前景元素会呈现出活力。前景和背景颜色的上下文特定混合可提高对比度。但是,如果使用设置自定义前景样式(不包括分层样式),例如,则会禁用活力。
在SwiftUI中,Material是一个用于创建视觉效果的类。根据提供的内容,我们可以重构代码如下:
```swift
enum Material {
case ultraThinMaterial
case thinMaterial
case regularMaterial
case thickMaterial
case ultraThickMaterial
}
struct ContentView: View {
static var ultraThinMaterial = Material.ultraThinMaterial
static var thinMaterial = Material.thinMaterial
static var regularMaterial = Material.regularMaterial
static var thickMaterial = Material.thickMaterial
static var ultraThickMaterial = Material.ultraThickMaterial
}
```
这样,我们将原来的静态变量分解成了枚举类型,并将其放在了一个名为ContentView的结构体中。这样可以更好地组织代码,使其更易于维护和理解。