有没有办法在SwiftUI中创建一个连接两个视图的弯曲箭头?

t98cgbkg  于 2023-02-21  发布在  Swift
关注(0)|答案(1)|浏览(121)

我想用箭头连接两个SwiftUI视图,一个指向另一个。例如,在此视图中:

struct ProfileIconWithPointer: View {
    var body: some View {
        VStack {
            Image(systemName: "person.circle.fill")
                .padding()
                .font(.title)
            Text("You")
                .offset(x: -20)
        }
    }
}

我有一个Text视图和一个Image视图,我希望有一个箭头从一个指向另一个,如下所示:

然而,我能找到的所有解决方案都依赖于先验地知道每个元素的位置,我不确定SwiftUI的声明性语法是否允许这样做。

1szpjjfi

1szpjjfi1#

可以使用下面的代码来显示箭头。

struct CurvedLine: Shape {
    let from: CGPoint
    let to: CGPoint
    var control: CGPoint
    
    var animatableData: AnimatablePair<CGFloat, CGFloat> {
        get {
            AnimatablePair(control.x, control.y)
        }
        set {
            control = CGPoint(x: newValue.first, y: newValue.second)
        }
    }
    
    func path(in rect: CGRect) -> Path {
        var path = Path()
        path.move(to: from)
        path.addQuadCurve(to: to, control: control)
        
        let angle = atan2(to.y - control.y, to.x - control.x)
        let arrowLength: CGFloat = 15
        let arrowPoint1 = CGPoint(x: to.x - arrowLength * cos(angle - .pi / 6), y: to.y - arrowLength * sin(angle - .pi / 6))
        let arrowPoint2 = CGPoint(x: to.x - arrowLength * cos(angle + .pi / 6), y: to.y - arrowLength * sin(angle + .pi / 6))
        
        path.move(to: to)
        path.addLine(to: arrowPoint1)
        path.move(to: to)
        path.addLine(to: arrowPoint2)
        
        return path
    }
}

您可以在代码中使用它,如下所示。

struct ContentView: View {
    var body: some View {
        VStack {
            Text("You")
                .alignmentGuide(.top) { d in
                    d[.bottom] - 30
                }
            Image(systemName: "person.circle.fill")
                .padding()
                .font(.title)
        }
        .overlay(
            CurvedLine(from: CGPoint(x: 50, y: 50),
                       to: CGPoint(x: 300, y: 200),
                       control: CGPoint(x: 100, y: -300))
                .stroke(Color.blue, lineWidth: 4)
        )
    }
}

这将如下所示。

根据你的情况修改代码。希望这对你有帮助。

相关问题