Reputation: 511
SwiftUI is missing a Pan gesture (that is, both scale and offset), so I was trying to create one. However, it appears that the Gesture struct depends on private classes. For example:
public struct PinchGesture: Gesture {
public struct PinchGestureValue: Equatable {
var scale: CGFloat
var anchor: UnitPoint
var offset: CGSize
var isPinching: Bool
}
public typealias Value = PinchGestureValue
public typealias Body = Never
var minimumScaleDelta: CGFloat
var minimumDistance: CGFloat
var coordinateSpace: CoordinateSpace
public init(minimumScaleDelta: CGFloat = 0.01, minimumDistance: CGFloat = 10, coordinateSpace: CoordinateSpace = .local) {
self.minimumScaleDelta = minimumScaleDelta
self.minimumDistance = minimumDistance
self.coordinateSpace = coordinateSpace
}
public static func _makeGesture(gesture: _GraphValue<PinchGesture>, inputs: _GestureInputs) -> _GestureOutputs<PinchGestureValue> {
// Unable to complete
}
}
This code cannot be completed, as the _GraphValue, _GestureInputs, and _GestureOutputs are private. Before I give in completely, I wanted to see if anyone has figured out a workaround.
Upvotes: 9
Views: 1607
Reputation: 385970
SwiftUI provides a default implementation of _makeGesture
:
extension Gesture where Self.Value == Self.Body.Value {
public static func _makeGesture(gesture: SwiftUI._GraphValue<Self>, inputs: SwiftUI._GestureInputs) -> SwiftUI._GestureOutputs<Self.Body.Value>
}
The difficulty here is the constraint Self.Value === Self.Body.Value
. That means your gesture's body
can't be declared to return some Gesture
, because some Gesture
can't satisfy the constraint (even if its Value
would match). So you have to give body
a specific type. The easiest solution is to use the AnyGesture
type eraser:
public struct PinchGesture: Gesture {
...
public var body: AnyGesture<PinchGestureValue> {
AnyGesture(
DragGesture(minimumDistance: 0, coordinateSpace: .global)
.map { PinchGestureValue($0) }
)
}
}
In this code, Swift can infer PinchGesture.Value = PinchGestureValue
and PinchGesture.Body = AnyGesture<PinchGestureValue>
. Then it can prove AnyGesture<PinchGestureValue>.Value == PinchGesture.Value
, so it can use the default implementation of _makeGesture
provided by SwiftUI.
Unfortunately, I doubt you can use this to create your PinchGesture
. Ultimately, your body
is still restricted to combining SwiftUI's primitive gestures, which don't give you access the current UIEvent
or UITouch
objects.
Upvotes: 5