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

SwiftUI中addArc与rotation3DEffect(X轴)组合异常求助

问题根源:Shape坐标系的误用

你遇到的核心问题是在Shape的path(in:)方法里直接用了屏幕中心作为圆弧的中心点,而非利用Shape自身的布局矩形rect的中心。SwiftUI的Shape是基于自身本地坐标系绘制的,rect参数代表的是这个Shape被分配到的布局区域——你直接用UIScreen.screenWidth/2和UIScreen.screenHeight/2会让圆弧的位置脱离Shape的本地坐标系,导致旋转时锚点和实际图形位置不匹配,X轴旋转自然会出现偏移或异常。

之前Y轴旋转看似正常只是巧合:Y轴旋转的方向加上图形位置的偏移刚好让视觉效果符合预期,但这并不是正确的实现方式。

修正方案

我们需要调整两个关键部分来解决问题:

1. 修正Shape的绘制逻辑,使用本地坐标系

把MyArc和MyArc2里的圆弧中心点改成rect的中心,这样图形会在Shape的布局区域内居中,旋转时会以正确的锚点(默认是UnitPoint.center)进行3D旋转:

struct MyArc : Shape {
    func path(in rect: CGRect) -> Path {
        var p = Path()
        // 使用当前Shape布局区域的中心作为圆弧中心
        let center = CGPoint(x: rect.midX, y: rect.midY)
        p.addArc(center: center, radius: 64, startAngle: .degrees(90), endAngle: .degrees(270), clockwise: true)
        return p
    }
}

struct MyArc2 : Shape {
    func path(in rect: CGRect) -> Path {
        var p = Path()
        let center = CGPoint(x: rect.midX, y: rect.midY)
        // 绘制水平方向的半圆,适配X轴3D旋转需求
        p.addArc(center: center, radius: 64, startAngle: .degrees(0), endAngle: .degrees(180), clockwise: true)
        return p
    }
}

2. 给Shape设置合适的布局Frame

因为我们的圆弧半径是64,所以Shape的布局区域至少需要128x128(直径大小)才能完整容纳圆弧。给每个Shape添加frame(width: 128, height: 128),确保rect的大小足够,并且图形在其中居中:

struct Globe2View: View {
    // ... 上面的MyArc和MyArc2定义 ...
    
    @Binding var turn:Double
    var body: some View {
        ZStack {
            ForEach(0..<12) { loop in
                MyArc()
                    .stroke(Color.blue, lineWidth: 2)
                    .frame(width: 128, height: 128) // 添加固定Frame
                    .rotation3DEffect(.degrees(self.turn + Double((loop * 30))), axis: (x: 0, y: -1, z: 0), perspective: 0)
            }
            ForEach(0..<12) { loop in
                MyArc2()
                    .stroke(Color.green, lineWidth: 2)
                    .frame(width: 128, height: 128) // 添加固定Frame
                    .rotation3DEffect(.degrees(self.turn + Double((loop * 30))), axis: (x: 1, y: 0, z: 0), perspective: 0)
            }
        }
    }
}

为什么原来的权宜方案能工作?

你之前用rotationEffect(.degrees(90))加offset,其实是通过2D旋转和偏移把错位的图形拉回了视觉上正确的位置,但这只是绕开了坐标系不匹配的问题,而非解决根源。现在修正后,图形在本地坐标系内居中,直接用X轴的rotation3DEffect就能得到正确的3D旋转效果,不需要额外的偏移和2D旋转。

完整修正后的代码
import SwiftUI
struct ContentView: View {
    @State var turn:Double = 0
    var body: some View {
        VStack {
            Image(systemName: "circle")
                .foregroundColor(Color.blue)
                .onTapGesture {
                    withAnimation(.linear(duration: 36)) {
                        self.turn = 360
                    }
                }
            Globe2View(turn: $turn)
        }
    }
}

struct Globe2View: View {
    struct MyArc : Shape {
        func path(in rect: CGRect) -> Path {
            var p = Path()
            let center = CGPoint(x: rect.midX, y: rect.midY)
            p.addArc(center: center, radius: 64, startAngle: .degrees(90), endAngle: .degrees(270), clockwise: true)
            return p
        }
    }
    struct MyArc2 : Shape {
        func path(in rect: CGRect) -> Path {
            var p = Path()
            let center = CGPoint(x: rect.midX, y: rect.midY)
            p.addArc(center: center, radius: 64, startAngle: .degrees(0), endAngle: .degrees(180), clockwise: true)
            return p
        }
    }
    @Binding var turn:Double
    var body: some View {
        ZStack {
            ForEach(0..<12) { loop in
                MyArc()
                    .stroke(Color.blue, lineWidth: 2)
                    .frame(width: 128, height: 128)
                    .rotation3DEffect(.degrees(self.turn + Double((loop * 30))), axis: (x: 0, y: -1, z: 0), perspective: 0)
            }
            ForEach(0..<12) { loop in
                MyArc2()
                    .stroke(Color.green, lineWidth: 2)
                    .frame(width: 128, height: 128)
                    .rotation3DEffect(.degrees(self.turn + Double((loop * 30))), axis: (x: 1, y: 0, z: 0), perspective: 0)
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者user3069232

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 21:52:36