SwiftUI Shape、边框、阴影、圆角等合集

为图形填充颜色和绘制边框

1
2
3
4
5
6
7
8
9
10
11
12
struct ContentView: View {
var body: some View {
Path { path in
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: 20, y: 300))
path.addLine(to: CGPoint(x: 300, y: 300))
path.closeSubpath()
}
.fill(.red)
.stroke(lineWidth: 5)
}
}

上面的做法会报错,原因是不能同时呼叫 fill & stroke

使用 ZStack

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct ContentView: View {
var body: some View {
ZStack {
Path { path in
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: 20, y: 300))
path.addLine(to: CGPoint(x: 300, y: 300))
path.closeSubpath()
}
.fill(.red)

Path { path in
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: 20, y: 300))
path.addLine(to: CGPoint(x: 300, y: 300))
path.closeSubpath()
}
.stroke(lineWidth: 5)
}
}
}

使用 overlay

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct Triangle: Shape {
func path(in rect: CGRect) -> Path {
Path { path in
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: 20, y: 300))
path.addLine(to: CGPoint(x: 300, y: 300))
path.closeSubpath()
}
}
}
struct ContentView: View {
var body: some View {
Triangle()
.fill(.red)
.overlay(
Triangle()
.stroke(lineWidth: 5)
)

}
}

Shape

填充颜色

1
2
3
4
5
6
7
8
Circle()
.fill(Color.blue)

Circle()
.foregroundColor(Color.pink)

Circle()
.background(.blue) // 注意,这个并不是

绘制边框

1
2
Circle()
.stroke(Color.blue, lineWidth: 20) // 空心圆轮廓宽度

椭圆形

1
2
Ellipse()       // 椭圆
.frame(width: 200, height: 100)

胶囊

1
2
Capsule()       // 胶囊形状
.frame(width: 200, height: 100)

矩形

1
2
3
4
5
Rectangle()     // 长方形
.frame(width: 200, height: 100)

RoundedRectangle(cornerRadius: 25.0) // 圆角长方形
.frame(width: 200, height: 100)

绘制边框

通过 .border 添加边框

1
2
3
4
5
6
7
struct ContentView: View {
var body: some View {
Text("Hello, world!")
.padding()
.border(.blue, width: 2)
}
}

通过 overlay

1
2
3
4
5
6
7
8
9
10
11
struct ContentView: View {
var body: some View {
Text("Hello, world!")
.padding()
.overlay(
Rectangle()
.strokeBorder(Color.blue, lineWidth: 2)
// .stroke(Color.blue, lineWidth: 2)
)
}
}

stroke()strokeBorder() 修饰符在形状周围绘制边框时,它们的行为略有不同:

strokeBorder() 修饰符将视图插入边框宽度的一半,然后应用笔触,这意味着整个边框都在视图内部绘制。 stroke() 修饰符绘制一个以视图边缘为中心的边框,这意味着边框的一半位于视图内部,一半位于视图外部。 重要说明:这两个修饰符仅适用于形状——您可以将 stroke()strokeBorder()CircleRectangleCapsule等一起使用,而不能与 TextImage 或其他非形状视图一起使用。 如果要在非形状视图周围绘制边框,则应改用 border() 修饰符。

绘制圆角

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
struct ContentView: View {
var body: some View {
VStack {
// 这种做法一定是错误的
Text("Hello, world!")
.padding()
.border(.blue, width: 2)
.cornerRadius(20)

// 这种,虽然效果上没有问题,但不推荐,因为用法是错误的
Text("Hello, world!")
.padding()
.background(.blue)
.cornerRadius(20)

// 下面2种才是正确的使用方式
Text("Hello, world!")
.padding()
.overlay(
RoundedRectangle(cornerRadius: 20)
.strokeBorder(Color.blue, lineWidth: 2)
)

Text("Hello, world!")
.padding()
.background(
RoundedRectangle(cornerRadius: 20)
.fill(.blue)
)
}
}
}

如果非要使用 .cornerRadius 可以这样

1
2
3
4
5
6
Text("Hello, world!")
.padding()
.background(
Color.blue
.cornerRadius(20)
)

结合 Shape 还可以这样:

1
2
3
4
5
6
7
Text("Hello, world!")
.padding()
.background(
Color.blue
.clipShape(.rect(cornerRadius: 20))
// .clipShape(.capsule) 胶囊
)

自定义圆角的位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
struct ContentView: View {
var body: some View {
Text("Hello, world!")
.padding()
.background(
RoundedCorners(color: .cyan, tl: 0, tr: 12, bl: 12, br: 0)
)
}
}

struct RoundedCorners: View {
var color: Color = .blue
var tl: CGFloat = 0.0
var tr: CGFloat = 0.0
var bl: CGFloat = 0.0
var br: CGFloat = 0.0

var body: some View {
GeometryReader { geometry in
Path { path in

let w = geometry.size.width
let h = geometry.size.height

// Make sure we do not exceed the size of the rectangle
let tr = min(min(self.tr, h/2), w/2)
let tl = min(min(self.tl, h/2), w/2)
let bl = min(min(self.bl, h/2), w/2)
let br = min(min(self.br, h/2), w/2)

path.move(to: CGPoint(x: w / 2.0, y: 0))
path.addLine(to: CGPoint(x: w - tr, y: 0))
path.addArc(center: CGPoint(x: w - tr, y: tr), radius: tr, startAngle: Angle(degrees: -90), endAngle: Angle(degrees: 0), clockwise: false)
path.addLine(to: CGPoint(x: w, y: h - br))
path.addArc(center: CGPoint(x: w - br, y: h - br), radius: br, startAngle: Angle(degrees: 0), endAngle: Angle(degrees: 90), clockwise: false)
path.addLine(to: CGPoint(x: bl, y: h))
path.addArc(center: CGPoint(x: bl, y: h - bl), radius: bl, startAngle: Angle(degrees: 90), endAngle: Angle(degrees: 180), clockwise: false)
path.addLine(to: CGPoint(x: 0, y: tl))
path.addArc(center: CGPoint(x: tl, y: tl), radius: tl, startAngle: Angle(degrees: 180), endAngle: Angle(degrees: 270), clockwise: false)
}
.fill(self.color)
}
}
}

阴影

1
2
3
4
5
6
7
8
struct ContentView: View {
var body: some View {
Text("Hello, world!")
.padding()
.background(Color.cyan)
.shadow(color: Color.black, radius: 10, x: 0, y: 0)
}
}

这种做法同时为 Text 与 background 添加了阴影。正确的做法应该是:

1
2
3
4
5
6
7
8
9
10
struct ContentView: View {
var body: some View {
Text("Hello, world!")
.padding()
.background(
Color.cyan
.shadow(color: Color.black, radius: 10, x: 0, y: 0)
)
}
}

SwiftUI Shape、边框、阴影、圆角等合集
https://wonderhoi.com/2025/08/26/SwiftUI-边框、阴影、圆角等合集/
作者
wonderhoi
发布于
2025年8月26日
许可协议