Grab View from Touch Event
In this article, we will explore how to retrieve a specific subview from a touch event in SwiftUI. We will dive deep into the details of touch events, view hierarchy, and subclassing views to achieve our goal.
Touch Events in SwiftUI
When working with SwiftUI views, it’s essential to understand how touch events work. When a user touches your app, the operating system sends a touch event to your app, which can be caught using a @StateVariable or a delegate method.
However, when dealing with complex view hierarchies, it can be challenging to determine which specific subview was touched. This is where subclassing views and converting touch coordinates comes into play.
Subclassing Views
To solve the problem of retrieving a specific subview from a touch event, we need to subclass our child views. By doing so, we gain access to their own view hierarchy and can calculate the touch position relative to each individual view.
Here’s an example of how you might do this:
// Create a new view class that inherits from `View`
struct Subview: View {
let superViewWidth: CGFloat = 300.0
let superViewHeight: CGFloat = 400.0
var body: some View {
// Your subview content here...
// Track touch events using the `onTapGesture` method
onTapGesture {
// Calculate the touch position relative to this view
guard let location = $0.location else { return }
// Convert the touch position from coordinate space to super-view's coordinate space
let pointInSuperView = CGPoint(x: (location.x * self.superViewWidth) / UIScreen.main.bounds.width,
y: (location.y * self.superViewHeight) / UIScreen.main.bounds.height)
// Use this converted point to determine which subview was touched
print(pointInSuperView)
}
}
}
By subclassing our child view and using the onTapGesture method, we can track touch events and calculate the touch position relative to each individual view.
Converting Touch Coordinates
To convert touch coordinates from coordinate space to super-view’s coordinate space, we use a simple scaling factor. The idea is that the subview’s origin (0, 0) is at the top-left corner of the super-view, and the subview’s width/height matches the super-view’s width/height.
We apply this scaling factor by dividing the touch location’s coordinates by the super-view’s bounds’ width and height. This gives us the equivalent point in the super-view’s coordinate space.
Converting Touch Coordinates Formula
Given a touch location at (x, y) with respect to the subview, we can calculate its equivalent point in the super-view’s coordinate space using the following formula:
let pointInSuperView = CGPoint(x: (x * self.superViewWidth) / UIScreen.main.bounds.width,
y: (y * self.superViewHeight) / UIScreen.main.bounds.height)
Using This Formula
Now that we have a way to convert touch coordinates, let’s see how we can use this information to determine which subview was touched.
When you create your child views using the Subview class, make sure each view has its own unique identifier. You can do this by creating a new constant for each view:
struct Subview1: View {
// ...
}
struct Subview2: View {
// ...
}
Then, when you receive a touch event, use the converted point to determine which subview was touched. Here’s an example:
// Track touch events using the `onTapGesture` method
onTapGesture {
// Calculate the touch position relative to this view
guard let location = $0.location else { return }
// Convert the touch position from coordinate space to super-view's coordinate space
let pointInSuperView = CGPoint(x: (location.x * self.superViewWidth) / UIScreen.main.bounds.width,
y: (location.y * self.superViewHeight) / UIScreen.main.bounds.height)
// Use this converted point to determine which subview was touched
if pointInSuperView.x < self.subview1Offset {
print("Subview 1 was touched")
} else if pointInSuperView.x >= self.subview1Offset + self.superViewWidth {
print("Subview 2 was touched")
}
}
By using this formula to convert touch coordinates and determining which subview was touched based on the converted point, we can achieve our goal of retrieving a specific subview from a touch event.
Conclusion
In this article, we explored how to retrieve a specific subview from a touch event in SwiftUI. By subclassing views, tracking touch events using onTapGesture, and converting touch coordinates, we can determine which subview was touched.
Remember, when working with complex view hierarchies, understanding the subtleties of view hierarchy and coordinate space conversion is crucial for achieving your design goals. With practice and patience, you’ll become proficient in using these techniques to solve challenging problems in iOS development.
Last modified on 2024-02-23