SwiftUI如何在已有形状上绘制其他形状且不导致底层形状偏移
问题原因
- 视图容器错误:当前
TouchCurveBasic的body中直接放置两个形状视图,SwiftUI默认会将多子视图放入垂直栈VStack中上下排列,而非层级叠加,因此会出现圆形挤压线条导致位置偏移的问题。 - Arc参数未生效:你定义的
Arc结构中声明了centerCustom参数,但实际绘制路径时没有使用该参数,永远以自身视图的中点作为圆心,传入的自定义坐标完全不生效。 - 坐标计算逻辑错误:
CurveCustomInit中使用全局变量DrawingZoneWidth、DrawingZoneHeight计算路径坐标,但你又为该视图指定了frame(width: 300, height: 300),应该用path(in:)方法传入的rect参数计算坐标,避免尺寸不匹配导致的偏移。
解决方案
将两个形状放入ZStack容器中实现层级叠加,同时修复上述逻辑错误,修改后的可运行代码如下:
import SwiftUI public var PointArray = [CGPoint]() public var PointArrayInit:Bool = false struct Arc: Shape { var startAngle: Angle var endAngle: Angle var clockwise: Bool var centerCustom:CGPoint func path(in rect: CGRect) -> Path { let rotationAdjustment = Angle.degrees(90) let modifiedStart = startAngle - rotationAdjustment let modifiedEnd = endAngle - rotationAdjustment var path = Path() // 修复:使用传入的自定义圆心 path.addArc(center: centerCustom, radius: 20, startAngle: modifiedStart, endAngle: modifiedEnd, clockwise: !clockwise) return path } } struct CurveCustomInit: Shape { private var Divider:Int = 10 func path(in rect: CGRect) -> Path { var path = Path() // 修复:用当前视图的实际尺寸计算坐标 let xStep:CGFloat = rect.width / CGFloat(Divider) let yStep:CGFloat = rect.midY var xStepLoopIncrement:CGFloat = 0 path.move(to: CGPoint(x: 0, y: yStep)) for _ in 0...Divider { let Point:CGPoint = CGPoint(x: xStepLoopIncrement, y: yStep) PointArray.append(Point) path.addLine(to: Point) xStepLoopIncrement += xStep } PointArrayInit = true return path } } struct TouchCurveBasic: View { var body: some View { if !PointArrayInit { // 修复:用ZStack实现层级叠加,两个视图共享同一坐标体系 ZStack(alignment: .topLeading) { CurveCustomInit() .stroke(Color.red, style: StrokeStyle(lineWidth: 10, lineCap: .round, lineJoin: .round)) .frame(width: 300, height: 300) Arc(startAngle: .degrees(0), endAngle: .degrees(360), clockwise: true, centerCustom: CGPoint(x: 50, y: 150)) .stroke(Color.blue, lineWidth: 4) } .frame(width: 300, height: 300) } } } struct TouchCurveBasic_Previews: PreviewProvider { static var previews: some View { TouchCurveBasic() } }
说明:上述代码调整了Arc的centerCustom坐标为(50,150),是因为ZStack高度为300,中点Y坐标为150,和红色线条的Y坐标一致,正好可以叠加在线条上,你可以根据需求自行调整圆心坐标。
额外优化建议:尽量不要用全局变量存储视图相关的状态,推荐使用@State、@Binding等SwiftUI原生状态管理属性包装器传递数据,避免出现视图不刷新、数据错乱的问题。
内容的提问来源于stack exchange,提问作者CharlieWhite
相关产品推荐
相关产品推荐

