TL;DR: I want to re-solve in SwiftUI this classic (and solved in UIKit) problem: how to pass along, to views behind, touches in transparent parts. Some approaches:
- Figure out if tap point has alpha == 0
- Providing a Bézier path to
contentShape()
E.g. I want taps in the transparent parts of the orange image to go through to the green image. The transparent areas may be non-connected, like the "holes" in these images.
Approach 1
@objc func handleTap(_ tgr: UITapGestureRecognizer) {
let p = tgr.location(in: self)
if pointIsOpaque(p) {
// Handle it now.
} else {
// Pass it through.
}
}
Finding the pointIsOpaque()
property is well-covered in
- How to get pixel color at location from UIimage scaled within a UIimageView
- Get alpha channel from UIImage rectangle
- CGContext.init() -- NULL color space no longer allowed
But it escapes me how to use this in SwiftUI — both deciding on pixel alpha, and how to pass events to the next view in the z-ordering. I'd rather use pure SwiftUI than wrapping with UIViewRepresentable
.
Approach 2
There is an existing "solution"; it raises as many challenges as it solves. This is to provide a path to View.contentShape()
. For connected transparent regions, this should be perfect — but how to calculate the path? The even-odd rule would help for simple disconnected regions. But what if the transparent part is a Cantor set? (JK, but it could be complicated.)
There is some info about calculating the opaque boundary:
Select similar pixels, draw bezier path around pixels and fill with color - iOS
http://www.pygame.org/docs/ref/mask.html#pygame.mask.Mask.outline
For my project I might be able to pre-calculate boundaries using pygame
. But doing transparent-hit-testing seems more direct.