提问人:hoptown 提问时间:11/7/2023 最后编辑:hoptown 更新时间:11/8/2023 访问量:41
SwiftUI- 仅使 png 图像的可见部分响应点击手势
SwiftUI- Make Only the Visible Part of png Image Respond to Tap Gesture
问:
我正在开发一个 iOS 应用程序(使用 SwiftUI),用户必须在其中点击图像才能获得响应。图像覆盖了另一个背景图像,因此它有意具有一些透明度。在一些图像中,有很多透明空间。这允许在“空白空间”中占用太多的可点击区域。我想对其进行改进,以便只有可见部分对点击手势做出响应。
截至目前,无论用户点击手势的哪个位置都会响应......即使用户点击图像的透明部分。我在这里发现了一个类似的问题 Make only visible parts of png clickable UIbutton swift,但它似乎在 ZStack 中处理多个图像。这是我拥有的一些代码:
Image("dog")
.resizable()
.scaledToFit()
.zIndex(1)
.clipped()
.gesture(simpleTap)
var simpleTap: some Gesture {
TapGesture()
.onEnded { _ in
playSound("dog.mp3")
}
}
答:
0赞
Sweeper
11/8/2023
#1
这里的关键是将图像的 设置为表示图像轮廓的 a。contentShape
Shape
如果您的图像是静态图像,那么您只需使用图像编辑器即可查找轮廓并将其导出为矢量图形格式。例如,在 GIMP 中,您可以选择图像的非透明部分,将所选内容转换为路径,然后将该路径导出为 SVG。(请参阅将任何图像文件的非透明部分转换为单个 svg 路径的最简单方法是什么?然后,您可以使用类似 PocketSVG 的东西读取 SVG,获取 ,并从中创建 SwiftUI。CGPath
Path
let svgURL = Bundle.main.url(forResource: "foo", withExtension: "svg")!
let paths = SVGBezierPath.pathsFromSVG(at: svgURL)
// you can save the 2 things above somewhere else, so that it doesn't get
// recomputed every time the view updates.
Image("dog")
.contentShape(Path(paths.first!.cgPath))
.onTapGesture {
print("Tapped")
}
.overlay { // overlay showing you where the tappable area is
Path(paths.first!.cgPath).stroke(lineWidth: 1)
}
如果图像是可调整大小的,则应相应地调整路径大小。您可以创建自己的内容来执行此操作:Shape
struct ResizablePath: Shape {
let path: Path
let originalSize: CGSize
func path(in rect: CGRect) -> Path {
let xScale = rect.width / originalSize.width
let yScale = rect.height / originalSize.height
print(path.boundingRect)
return path.applying(.init(scaleX: xScale, y: yScale).translatedBy(x: rect.minX, y: rect.minY))
}
}
let svgURL = Bundle.main.url(forResource: "foo", withExtension: "svg")!
let paths = SVGBezierPath.pathsFromSVG(at: svgURL)
// get the original size from a UIImage
let size = UIImage(named: "dog")!.size
Image("dog")
.resizable()
.contentShape(ResizablePath(path: Path(paths.first!.cgPath), originalSize: size))
.scaledToFit()
.onTapGesture {
print("Tapped")
}
.overlay {
ResizablePath(path: Path(paths.first!.cgPath), originalSize: size).stroke(lineWidth: 1)
}
评论
contentShape()
Shape