在图像之间绘制箭头 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))
}
}
}
我正在开发一个 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))
}
}
}