You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 02:06:01