在 SwiftUI 中,stroke() 描述符是一个用于为形状添加边框(Stroke)的修饰符。它可以以多种方式配置边框的颜色、线宽和线条样式,例如虚线或其他自定义样式。
以下是 stroke 修饰符的详细使用说明。
语法概述#
1. 基本形式#
.stroke(Color, lineWidth: CGFloat)Color:边框的颜色,通常使用系统定义的颜色或自定义的Color。lineWidth:边框的宽度(浮点值,单位为点)。
2. 自定义线条样式#
.stroke(style: StrokeStyle)StrokeStyle:用于创建自定义的线条样式(包括虚线、线帽等)。
基础用法示例#
示例 1:为形状添加简单的边框#
import SwiftUI
struct ContentView: View {
var body: some View {
Circle()
.stroke(Color.blue, lineWidth: 5) // 蓝色的边框,线宽为 5 点
.frame(width: 100, height: 100)
}
}效果:
- 一个半径为 50 点的圆形,边框为蓝色,宽度 5 点。
进阶用法:调整线条样式#
通过 StrokeStyle 可以更详细地定制边框样式,包括:
- 线条宽度(
lineWidth) - 线条的端点形状(
lineCap) - 拐角的形状(
lineJoin) - 虚线样式(
dash和dashPhase)
StrokeStyle 常见参数:
StrokeStyle(lineWidth: CGFloat = 1,
lineCap: CGLineCap = .butt,
lineJoin: CGLineJoin = .miter,
miterLimit: CGFloat = 10,
dash: [CGFloat] = [],
dashPhase: CGFloat = 0)示例 2:自定义线条端点形状和拐角形状#
import SwiftUI
struct ContentView: View {
var body: some View {
RoundedRectangle(cornerRadius: 20)
.stroke(Color.red, style: StrokeStyle(lineWidth: 5,
lineCap: .round,
lineJoin: .bevel))
.frame(width: 200, height: 100)
}
}参数解析:#
lineCap: 表示线条端点的形状,这里设置为.round,端点变为圆形。- 常用值:
.butt(默认值):直角结束。.round:圆形端点。.square:方形端点。
- 常用值:
lineJoin: 表示线条拐角的形状,这里设置为.bevel,拐角变为斜角。- 常用值:
.miter(默认值):尖角拐角(变尖)。.round:圆角拐角。.bevel:切角拐角。
- 常用值:
效果:
- 一个四边形,边缘有斜角 (Bevel),每条边的端点为圆形(Round)。
示例 3:创建虚线样式#
StrokeStyle 中的 dash 参数用于设置虚线的模式。dash 是一个数组,其中的数值交替表示绘制线段和跳过的长度。
import SwiftUI
struct ContentView: View {
var body: some View {
Circle()
.stroke(Color.green, style: StrokeStyle(lineWidth: 4,
dash: [10, 5],
dashPhase: 0))
.frame(width: 100, height: 100)
}
}参数解析:#
dash:一个数组,依次交替表示线段长度和间隔长度。[10, 5]表示:绘制 10 点长度的线,然后跳过 5 点长度的空白。
dashPhase:虚线的偏移量,控制虚线的起始部分。如果偏移量不为零,它会“滚动”虚线的绘图位置。
效果:
- 一个绿色的圆形边框,显示有规律的虚线(每段线长为 10 点,间隔为 5 点)。
示例 4:带动态偏移的虚线#
如果想让虚线不断滚动,可以动态调整 dashPhase 的值,例如借助 Timer 动态更新视图。
import SwiftUI
struct ContentView: View {
@State private var phase: CGFloat = 0
var body: some View {
Circle()
.stroke(Color.orange, style: StrokeStyle(lineWidth: 4,
dash: [10, 5],
dashPhase: phase))
.frame(width: 100, height: 100)
.onAppear {
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { _ in
phase -= 5 // 动态调整偏移
}
}
}
}效果:
- 虚线圆边框会不断“滚动”。
示例 5:组合填充和边框#
在实践中,经常需要为形状同时添加填充颜色(内部)和边框颜色(外部)。可以通过 .stroke() 与 .fill() 的组合实现。
import SwiftUI
struct ContentView: View {
var body: some View {
Circle()
.fill(Color.yellow) // 内部填充为黄色
.overlay(
Circle()
.stroke(Color.blue, lineWidth: 5) // 外部边框为蓝色
)
.frame(width: 100, height: 100)
}
}效果:
- 一个内部填充为黄色的圆形,外层有蓝色边框。
注意:#
.stroke() 本身只会绘制边框,不能设置填充。若需要同时具备填充,可结合 .fill() 或 .background()。
完整的 StrokeStyle 参数#
StrokeStyle 提供了一系列参数,用于高度自定义边框的绘制行为。参数功能如下:
| 参数名 | 描述 | 示例值 |
|---|---|---|
lineWidth | 边框的宽度(单位:点) | 4, 10 |
lineCap | 定义线条端点的形状,适用于开放路径(CGLineCap)。 | .butt, .round |
lineJoin | 定义线条拐角的形状,适用于路径的拐角(CGLineJoin)。 | .miter, .round |
miterLimit | 定义尖角的限制(仅当 lineJoin = .miter 时生效),限制拐角延伸的长度 | 默认值 10 |
dash | 设置虚线样式的间隔模式(绘制段长度与空白段长度数组)。 | [5, 10], [2, 4, 6] |
dashPhase | 控制虚线起始偏移量。正值偏移使虚线滚动,可用于动画。 | 0, 5, -5 |
常见用途#
绘制带边框的基本形状: 使用
.stroke()可以为Circle、RoundedRectangle、Capsule等形状添加边框。创建虚线或其他自定义样式的边框: 使用
StrokeStyle中的dash和dashPhase创建虚线样式,动态更新dashPhase实现动画。分层图形:
.stroke()常与.fill()配合,满足填充和描边的双重需求。
总结#
stroke() 描述符是 SwiftUI 中一种简单而灵活的方式,用于为形状添加边框。它可以通过简单的参数如颜色和线宽满足基本需求,也可以通过强大的 StrokeStyle 为边框样式提供完整的自定义支持。
常用写法总结:#
| 修饰符(需求) | 示例 | 效果 |
|---|---|---|
| 简单边框 | .stroke(Color.red, lineWidth: 5) | 固定宽度的彩色边框 |
| 自定义虚线 | .stroke(style: StrokeStyle(lineWidth: 4, dash: [5, 3])) | 连续虚线 |
| 动态虚线 | 使用 dashPhase 动态调整 | 虚线滚动动画 |
| 结合填充和背景 | .fill(Color.green).overlay(Circle().stroke(Color.red, ...)) | 同时具备填充颜色和边框 |
通过合理利用 stroke() 和 StrokeStyle,你可以在 SwiftUI 中创建多种样式的形状和边框,满足各种视觉设计需求!
strokeBorder 区别#
在 SwiftUI 中,stroke 和 strokeBorder 都是用于为形状(Shape)添加边框的修饰符,但它们的绘制方式和布局行为有显著区别。以下是两者的对比和适用场景:
1. stroke#
作用:沿形状的原始路径(路径的中心线)绘制边框,边框的宽度向内外等距扩展。
布局影响:边框会超出形状的原始边界,导致视图的整体尺寸(布局空间)增大。
示例:
Circle() .stroke(Color.blue, lineWidth: 10) .frame(width: 100, height: 100)- 效果:边框的宽度会向圆形内外各扩展
5pt(总宽度10pt),最终视图的布局尺寸为110x110(原始100x100+ 边框10pt)。
- 效果:边框的宽度会向圆形内外各扩展
适用场景:
- 当需要边框不影响形状内部的绘制区域时。
- 当允许边框超出原始形状的布局空间时。
2. strokeBorder#
作用:将边框完全绘制在形状的原始边界内部,边框宽度不会超出原始形状的尺寸。
布局影响:视图的整体尺寸保持与原始形状一致,边框的宽度会向内“压缩”内容。
示例:
Circle() .strokeBorder(Color.red, lineWidth: 10) .frame(width: 100, height: 100)- 效果:边框完全在
100x100的圆形内部,最终视图的布局尺寸仍为100x100,但边框会向内占用空间(实际可见的圆形直径为80pt)。
- 效果:边框完全在
适用场景:
- 当需要严格保持视图的布局尺寸不变时。
- 当边框需要完全包含在形状内部时(如避免覆盖相邻视图)。
3. 关键区别对比#
| 特性 | stroke | strokeBorder |
|---|---|---|
| 边框位置 | 向内外扩展,超出原始边界 | 完全在原始边界内部 |
| 布局尺寸 | 增加(边框宽度影响布局) | 保持原始尺寸不变 |
| 视觉大小 | 原始形状 + 边框宽度 | 原始形状 - 边框宽度 |
| 适用场景 | 允许布局扩展的边框 | 严格固定布局尺寸的边框 |
4. 代码验证#
通过叠加两个形状观察差异:
struct StrokeDemo: View {
var body: some View {
VStack(spacing: 20) {
// stroke:边框超出布局
Circle()
.stroke(Color.blue, lineWidth: 10)
.frame(width: 100, height: 100)
.background(Color.gray.opacity(0.2))
// strokeBorder:边框不超出布局
Circle()
.strokeBorder(Color.red, lineWidth: 10)
.frame(width: 100, height: 100)
.background(Color.gray.opacity(0.2))
}
}
}- 效果:
stroke的蓝色边框会导致灰色背景区域变大。strokeBorder的红色边框保持灰色背景区域为100x100。
5. 高级用法#
自定义
StrokeStyle:两者都支持自定义样式(如虚线、端点样式):Circle() .strokeBorder( Color.green, style: StrokeStyle( lineWidth: 5, dash: [10] ) )组合形状:当形状需要叠加边框时,
strokeBorder更适合确保布局稳定:ZStack { Circle() .fill(Color.yellow) Circle() .strokeBorder(Color.black, lineWidth: 2) } .frame(width: 100, height: 100)
总结#
- 使用
stroke:当需要边框向外扩展,且不介意视图布局尺寸增大时。 - 使用
strokeBorder:当需要边框完全在原始形状内部,且严格保持布局尺寸不变时。