在图像之间绘制箭头 macOS

Drawing arrows between images macOS

我正在开发一个 SwiftUI 视图,它应该显示从磁盘加载的图像,图像之间带有箭头。我的视图结构基本上是这样的:

ScrollView
- HStack
-- ForEach
--- GeometryReader
---- Image

我的想法是,我可以只使用 GeometryReader 找到每个图像在 ScrollView 中的当前位置,然后使用路径在两个图像之间画一条线。我至少在正确的轨道上吗?我还注意到使用 GeometryReader 会在很大程度上降低性能,并且不认为这是获取每个图像位置的正确方法,除非我只是错误地使用它。

这是我目前的代码:

import SwiftUI

struct ScreenshotView: View {
    let screenshots = getScreenshots()
    

    var body: some View {
        ScrollView(.horizontal, showsIndicators: false) {
            HStack(spacing: 0) {
                ForEach(screenshots, id: \.self) { screenshot in
                    GeometryReader { geo in
                        // have to use NSImage to load from disk
                        if let nsImage = NSImage(
                            contentsOf: screenshot.path) {
                            Button(action: {
                                print("Trying to open: ", screenshot.path)
                                NSWorkspace.shared.open(screenshot.path)
                            }) {
                                Image(nsImage: nsImage)
                                    .resizable()
                                    .frame(width: 50, height: 100)
                                    .aspectRatio(contentMode: .fit)
                                    .padding()
                                    .coordinateSpace(name: "image")
                            }
                            .buttonStyle(PlainButtonStyle())
                            .help("\(geo.frame(in: .global).midX)")
                        }
                    }
                    .frame(width: 50, height: 100)
                    .padding()
                }
            }
        }
        .padding()
    }
}

感谢您的帮助!

您不需要 GeometryReader。只需将箭头放在 HStack 中的图像之间。如果您不需要间距,请在 HStack 中进行调整,例如spacing: 0.

Shape 本身就是一个单独的视图,它不需要绝对位置点,而是根据父视图调整自身的大小,或者像本例中的 [=16= 给出的大小一样].

struct ContentView: View {
    var body: some View {
        
        ScrollView(.horizontal, showsIndicators: false) {
            HStack {
                ForEach(0..<10) { _ in
                    Rectangle().fill(.gray)
                        .frame(width: 50, height: 50)
                    ArrowShape()
                        .stroke(lineWidth: 2)
                        .frame(width: 50, height: 20)
                }
            }
        }
        .padding()
    }
}

struct ArrowShape: Shape{
    
    func path(in rect: CGRect) -> Path {
        
        let delta = rect.height / 2  // height of arrow tip legs
        
        return Path{ path in
            path.move(to: CGPoint(x: 0, y: rect.midY))
            path.addLine(to: CGPoint(x: rect.maxX, y: rect.midY))
            
            path.move(to: CGPoint(x: rect.maxX - delta, y: rect.midY - delta))
            path.addLine(to: CGPoint(x: rect.maxX, y: rect.midY))
            path.addLine(to: CGPoint(x: rect.maxX - delta, y: rect.midY + delta))
        }
    }
}