在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 where T.Element? >= (minUInt8Value, minUInt8Value, minUInt8Value) && T.Element? <= (maxUInt8Value, maxUInt8Value, maxUInt8Value) {} // clamping the value between [MIN_VALUE, MAX_VALUE] and [0, MAX_VALUE] for uicolor components.

//使用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的结构体中。这样可以更好地组织代码,使其更易于维护和理解。