1 import SwiftUI
2
3 struct HexagonParameters {
4 struct Segment {
5 let useWidth: (CGFloat, CGFloat, CGFloat)
6 let xFactors: (CGFloat, CGFloat, CGFloat)
7 let useHeight: (CGFloat, CGFloat, CGFloat)
8 let yFactors: (CGFloat, CGFloat, CGFloat)
9 }
10
11 static let adjustment: CGFloat = 0.085
12
13 static let points = [
14 Segment(
15 useWidth: (1.00, 1.00, 1.00),
16 xFactors: (0.60, 0.40, 0.50),
17 useHeight: (1.00, 1.00, 0.00),
18 yFactors: (0.05, 0.05, 0.00)
19 ),
20 Segment(
21 useWidth: (1.00, 1.00, 0.00),
22 xFactors: (0.05, 0.00, 0.00),
23 useHeight: (1.00, 1.00, 1.00),
24 yFactors: (0.20 + adjustment, 0.30 + adjustment, 0.25 + adjustment)
25 ),
26 Segment(
27 useWidth: (1.00, 1.00, 0.00),
28 xFactors: (0.00, 0.05, 0.00),
29 useHeight: (1.00, 1.00, 1.00),
30 yFactors: (0.70 - adjustment, 0.80 - adjustment, 0.75 - adjustment)
31 ),
32 Segment(
33 useWidth: (1.00, 1.00, 1.00),
34 xFactors: (0.40, 0.60, 0.50),
35 useHeight: (1.00, 1.00, 1.00),
36 yFactors: (0.95, 0.95, 1.00)
37 ),
38 Segment(
39 useWidth: (1.00, 1.00, 1.00),
40 xFactors: (0.95, 1.00, 1.00),
41 useHeight: (1.00, 1.00, 1.00),
42 yFactors: (0.80 - adjustment, 0.70 - adjustment, 0.75 - adjustment)
43 ),
44 Segment(
45 useWidth: (1.00, 1.00, 1.00),
46 xFactors: (1.00, 0.95, 1.00),
47 useHeight: (1.00, 1.00, 1.00),
48 yFactors: (0.30 + adjustment, 0.20 + adjustment, 0.25 + adjustment)
49 )
50 ]
51 }
在中,为徽章添加形状并应用修改器将形状转换为视图。Badge.swift
Path
fill()
您可以使用路径组合线条,曲线和其他绘图基元,以形成更复杂的形状,如徽章的六边形背景。
1 import SwiftUI
2
3 struct Badge: View {
4 var body: some View {
5 Path { path in
6
7 }
8 .fill(Color.black)
9 }
10 }
11
12 struct Badge_Previews: PreviewProvider {
13 static var previews: some View {
14 Badge()
15 }
16 }
第3步
该move(to:)
方法将绘图光标移动到形状的边界内,就好像假想的钢笔或铅笔悬停在该区域上,等待开始绘制。
1 import SwiftUI
2
3 struct Badge: View {
4 var body: some View {
5 Path { path in
6 var width: CGFloat = 100.0
7 let height = width
8 path.move(to: CGPoint(x: width * 0.95, y: height * 0.20))
9 }
10 .fill(Color.black)
11 }
12 }
13
14 struct Badge_Previews: PreviewProvider {
15 static var previews: some View {
16 Badge()
17 }
18 }
第4步
绘制形状数据的每个点的线条以创建粗糙的六边形形状。
该方法需要一个点并绘制它。连续调用在前一点开始一行并继续到新点。addLine(to:)
addLine(to:)
不要担心你的六角形看起来有点不寻常; 那是现在的预期行为。在接下来的几个步骤中,您将努力使六边形看起来更像本节开头所示的徽章形状
1 import SwiftUI
2
3 struct Badge: View {
4 var body: some View {
5 Path { path in
6 var width: CGFloat = 100.0
7 let height = width
8 path.move(to: CGPoint(x: width * 0.95, y: height * 0.20))
9
10 HexagonParameters.points.forEach {
11 path.addLine(
12 to: .init(
13 x: width * $0.useWidth.0 * $0.xFactors.0,
14 y: height * $0.useHeight.0 * $0.yFactors.0
15 )
16 )
17 }
18 }
19 .fill(Color.black)
20 }
21 }
22
23 struct Badge_Previews: PreviewProvider {
24 static var previews: some View {
25 Badge()
26 }
27 }
第5步
使用该方法绘制徽章角的Bézier曲线。addQuadCurve(to:control:)
1 import SwiftUI
2
3 struct Badge: View {
4 var body: some View {
5 Path { path in
6 var width: CGFloat = 100.0
7 let height = width
8 path.move(
9 to: CGPoint(
10 x: width * 0.95,
11 y: height * (0.20 + HexagonParameters.adjustment)
12 )
13 )
14
15 HexagonParameters.points.forEach {
16 path.addLine(
17 to: .init(
18 x: width * $0.useWidth.0 * $0.xFactors.0,
19 y: height * $0.useHeight.0 * $0.yFactors.0
20 )
21 )
22
23 path.addQuadCurve(
24 to: .init(
25 x: width * $0.useWidth.1 * $0.xFactors.1,
26 y: height * $0.useHeight.1 * $0.yFactors.1
27 ),
28 control: .init(
29 x: width * $0.useWidth.2 * $0.xFactors.2,
30 y: height * $0.useHeight.2 * $0.yFactors.2
31 )
32 )
33 }
34 }
35 .fill(Color.black)
36 }
37 }
38
39 struct Badge_Previews: PreviewProvider {
40 static var previews: some View {
41 Badge()
42 }
43 }
第6步
将徽章路径包裹在一起,以便徽章可以使用其包含视图的大小,该视图定义大小而不是硬编码值()。GeometryReader
100
使用最小的几何体的两个维度可以在徽章的包含视图不是正方形时保留纵横比。
1 import SwiftUI
2
3 struct Badge: View {
4 var body: some View {
5 GeometryReader { geometry in
6 Path { path in
7 var width: CGFloat = min(geometry.size.width, geometry.size.height)
8 let height = width
9 path.move(
10 to: CGPoint(
11 x: width * 0.95,
12 y: height * (0.20 + HexagonParameters.adjustment)
13 )
14 )
15
16 HexagonParameters.points.forEach {
17 path.addLine(
18 to: .init(
19 x: width * $0.useWidth.0 * $0.xFactors.0,
20 y: height * $0.useHeight.0 * $0.yFactors.0
21 )
22 )
23
24 path.addQuadCurve(
25 to: .init(
26 x: width * $0.useWidth.1 * $0.xFactors.1,
27 y: height * $0.useHeight.1 * $0.yFactors.1
28 ),
29 control: .init(
30 x: width * $0.useWidth.2 * $0.xFactors.2,
31 y: height * $0.useHeight.2 * $0.yFactors.2
32 )
33 )
34 }
35 }
36 .fill(Color.black)
37 }
38 }
39 }
40
41 struct Badge_Previews: PreviewProvider {
42 static var previews: some View {
43 Badge()
44 }
45 }
第7步
使用和调整变量将徽章置于其几何体中心。xScale
xOffset
1 import SwiftUI
2
3 struct Badge: View {
4 var body: some View {
5 GeometryReader { geometry in
6 Path { path in
7 var width: CGFloat = min(geometry.size.width, geometry.size.height)
8 let height = width
9 let xScale: CGFloat = 0.832
10 let xOffset = (width * (1.0 - xScale)) / 2.0
11 width *= xScale
12 path.move(
13 to: CGPoint(
14 x: xOffset + width * 0.95,
15 y: height * (0.20 + HexagonParameters.adjustment)
16 )
17 )
18
19 HexagonParameters.points.forEach {
20 path.addLine(
21 to: .init(
22 x: xOffset + width * $0.useWidth.0 * $0.xFactors.0,
23 y: height * $0.useHeight.0 * $0.yFactors.0
24 )
25 )
26
27 path.addQuadCurve(
28 to: .init(
29 x: xOffset + width * $0.useWidth.1 * $0.xFactors.1,
30 y: height * $0.useHeight.1 * $0.yFactors.1
31 ),
32 control: .init(
33 x: xOffset + width * $0.useWidth.2 * $0.xFactors.2,
34 y: height * $0.useHeight.2 * $0.yFactors.2
35 )
36 )
37 }
38 }
39 .fill(Color.black)
40 }
41 }
42 }
43
44 struct Badge_Previews: PreviewProvider {
第8步
使用渐变替换徽章的纯黑色背景以匹配设计。
1 import SwiftUI
2
3 struct Badge: View {
4 var body: some View {
5 GeometryReader { geometry in
6 Path { path in
7 var width: CGFloat = min(geometry.size.width, geometry.size.height)
8 let height = width
9 let xScale: CGFloat = 0.832
10 let xOffset = (width * (1.0 - xScale)) / 2.0
11 width *= xScale
12 path.move(
13 to: CGPoint(
14 x: xOffset + width * 0.95,
15 y: height * (0.20 + HexagonParameters.adjustment)
16 )
17 )
18
19 HexagonParameters.points.forEach {
20 path.addLine(
21 to: .init(
22 x: xOffset + width * $0.useWidth.0 * $0.xFactors.0,
23 y: height * $0.useHeight.0 * $0.yFactors.0
24 )
25 )
26
27 path.addQuadCurve(
28 to: .init(
29 x: xOffset + width * $0.useWidth.1 * $0.xFactors.1,
30 y: height * $0.useHeight.1 * $0.yFactors.1
31 ),
32 control: .init(
33 x: xOffset + width * $0.useWidth.2 * $0.xFactors.2,
34 y: height * $0.useHeight.2 * $0.yFactors.2
35 )
36 )
37 }
38 }
39 .fill(LinearGradient(
40 gradient: .init(colors: [Self.gradientStart, Self.gradientEnd]),
41 startPoint: .init(x: 0.5, y: 0),
42 endPoint: .init(x: 0.5, y: 0.6)
43 ))
44 }
45 }
46 static let gradientStart = Color(red: 239.0 / 255, green: 120.0 / 255, blue: 221.0 / 255)
47 static let gradientEnd = Color(red: 239.0 / 255, green: 172.0 / 255, blue: 120.0 / 255)
48 }
49
50 struct Badge_Previews: PreviewProvider {
51 static var previews: some View {
52 Badge()
53 }
54 }
第9步
将修改器应用于渐变填充。aspectRatio(_:contentMode:)
通过保持1:1的宽高比,徽章保持其位于视图中心的位置,即使其祖先视图不是正方形。
1 import SwiftUI
2
3 struct Badge: View {
4 var body: some View {
5 GeometryReader { geometry in
6 Path { path in
7 var width: CGFloat = min(geometry.size.width, geometry.size.height)
8 let height = width
9 let xScale: CGFloat = 0.832
10 let xOffset = (width * (1.0 - xScale)) / 2.0
11 width *= xScale
12 path.move(
13 to: CGPoint(
14 x: xOffset + width * 0.95,
15 y: height * (0.20 + HexagonParameters.adjustment)
16 )
17 )
18
19 HexagonParameters.points.forEach {
20 path.addLine(
21 to: .init(
22 x: xOffset + width * $0.useWidth.0 * $0.xFactors.0,
23 y: height * $0.useHeight.0 * $0.yFactors.0
24 )
25 )
26
27 path.addQuadCurve(
28 to: .init(
29 x: xOffset + width * $0.useWidth.1 * $0.xFactors.1,
30 y: height * $0.useHeight.1 * $0.yFactors.1
31 ),
32 control: .init(
33 x: xOffset + width * $0.useWidth.2 * $0.xFactors.2,
34 y: height * $0.useHeight.2 * $0.yFactors.2
35 )
36 )
37 }
38 }
39 .fill(LinearGradient(
40 gradient: .init(colors: [Self.gradientStart, Self.gradientEnd]),
41 startPoint: .init(x: 0.5, y: 0),
42 endPoint: .init(x: 0.5, y: 0.6)
43 ))
44 .aspectRatio(1, contentMode: .fit)
45 }
46 }
47 static let gradientStart = Color(red: 239.0 / 255, green: 120.0 / 255, blue: 221.0 / 255)
48 static let gradientEnd = Color(red: 239.0 / 255, green: 172.0 / 255, blue: 120.0 / 255)
49 }
50
51 struct Badge_Previews: PreviewProvider {
52 static var previews: some View {
53 Badge()
54 }
55 }