SwiftUI中如何将Shape的自定义顶点设为锚点精准定位?
问题描述
我创建了如下Triangle形状:
struct Triangle: Shape { func path(in rect: CGRect) -> Path { Path { path in path.move(to: CGPoint.zero) path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY)) path.addLine(to: CGPoint(x: rect.maxX, y: rect.minY)) } } }
我希望将它的顶点(即Shape空间中的CGPoint.zero)精准定位到指定坐标(如下例中红色矩形所在位置):
struct MapShapes: View { @State var angle: Double = 0.0 var body: some View { ZStack { Triangle() .frame(width: 40, height: 40) .position(CGPoint(x: 100, y: 100)) Rectangle() .foregroundColor(.red) .frame(width: 10, height: 10) .position(CGPoint(x: 100, y: 100)) } } }
当前效果:三角形的中心与红色矩形重合,顶点位于红色矩形的左上方。
预期效果:三角形的CGPoint.zero顶点与红色矩形完全重合,三角形从该点向下向右展开。
SwiftUI默认以Shape的中心作为锚点,请问能否将锚点改为Shape空间中的.zero点?除了手动计算中心偏移量(需考虑Shape尺寸),有没有更优方案?是否需要采用ZStack之外的方法叠加定位多个形状?
解决方案
方法1:使用alignmentGuide自定义锚点(最优方案)
通过alignmentGuide直接将视图的默认中心锚点替换为Shape的CGPoint.zero(对应视图的.topLeading位置),无需手动计算偏移量:
struct MapShapes: View { @State var angle: Double = 0.0 var body: some View { ZStack { Triangle() .frame(width: 40, height: 40) // 将视图的中心锚点替换为topLeading(即Shape的CGPoint.zero) .alignmentGuide(.center) { dimensions in dimensions[.topLeading] } .position(x: 100, y: 100) Rectangle() .foregroundColor(.red) .frame(width: 10, height: 10) .position(x: 100, y: 100) } } }
方法2:调整Shape的路径原点
修改Triangle的路径逻辑,让顶点直接基于传入的rect的.topLeading位置绘制,配合frame的alignment使用:
struct Triangle: Shape { func path(in rect: CGRect) -> Path { Path { path in // 直接以rect的topLeading作为顶点,避免坐标偏移 path.move(to: rect.topLeading) path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY)) path.addLine(to: CGPoint(x: rect.maxX, y: rect.minY)) } } } struct MapShapes: View { @State var angle: Double = 0.0 var body: some View { ZStack { Triangle() .frame(width: 40, height: 40, alignment: .topLeading) .alignmentGuide(.center) { $0[.topLeading] } .position(x: 100, y: 100) Rectangle() .foregroundColor(.red) .frame(width: 10, height: 10) .position(x: 100, y: 100) } } }
方法3:offset配合frame(alignment:)
如果不想使用alignmentGuide,可以通过frame的alignment将Shape顶点对齐到frame左上角,再用offset将该点移到目标位置:
struct MapShapes: View { @State var angle: Double = 0.0 let target = CGPoint(x: 100, y: 100) var body: some View { ZStack { Triangle() .frame(width: 40, height: 40, alignment: .topLeading) .offset(x: target.x, y: target.y) Rectangle() .foregroundColor(.red) .frame(width: 10, height: 10) .position(target) } } }
关于ZStack的使用
ZStack是SwiftUI中叠加视图的标准方案,完全可以满足你的需求,不需要替换为其他布局容器。上述所有方案都基于ZStack实现,定位精准且代码简洁。
内容的提问来源于stack exchange,提问作者Ze Jibe
相关产品推荐
相关产品推荐

