Post

Replies

Boosts

Views

Activity

Reply to Getting incorrect force values on first touch - iPad Pro M2 / Apple Pencil 2
Here is some of my code // // StrokeGestureRecognizer.swift // Animate3D // // Created by Georg Graf on 07.07.23. // import UIKit class StrokeGestureRecognizer: UIGestureRecognizer { // MARK: - Configuration var collectsCoalescedTouches = true var usesPredictedSamples = true var coordinateSpaceView: UIView? var ensuredReferenceView: UIView { if let view = coordinateSpaceView { return view } else { return view! } } /// A Boolean value that determines whether the gesture recognizer tracks Apple Pencil or finger touches. /// - Tag: isForPencil var isForPencil: Bool = true { didSet { if isForPencil { allowedTouchTypes = [UITouch.TouchType.pencil.rawValue as NSNumber] } else { allowedTouchTypes = [UITouch.TouchType.direct.rawValue as NSNumber] } } } // MARK: - State var trackedTouch: UITouch? var collectForce = true var stroke = Stroke() // MARK: - Line data collection /// Appends touch data to the stroke sample. /// - Tag: appendTouches func append(touches: Set<UITouch>, event: UIEvent?) -> Bool { // Check that we have a touch to append, and that touches // doesn't contain it. guard let touchToAppend = trackedTouch, touches.contains(touchToAppend) == true else { return false } if collectsCoalescedTouches { if let event = event { let coalescedTouches = event.coalescedTouches(for: touchToAppend)! let lastIndex = coalescedTouches.count - 1 for index in 0..<lastIndex { let location = coalescedTouches[index].preciseLocation(in: ensuredReferenceView) stroke.saveStrokeSample(coordinates: location, force: getForceRatio(touch: coalescedTouches[index])) } let location = coalescedTouches[lastIndex].preciseLocation(in: ensuredReferenceView) stroke.saveStrokeSample(coordinates: location, force: getForceRatio(touch: coalescedTouches[lastIndex])) } } else { let location = touchToAppend.preciseLocation(in: ensuredReferenceView) stroke.saveStrokeSample(coordinates: location, force: getForceRatio(touch: touchToAppend)) } if usesPredictedSamples && stroke.state == .active { if let predictedTouches = event?.predictedTouches(for: touchToAppend) { for touch in predictedTouches { // do nothing for now } } } return true } private func getForceRatio(touch: UITouch) -> CGFloat { print("touch.force: \(touch.force), maxPossible: \(touch.maximumPossibleForce)") return touch.force / touch.maximumPossibleForce } // MARK: - Touch handling methods /// A set of functions that track touches. /// - Tag: HandleTouches override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { stroke = Stroke() if trackedTouch == nil { trackedTouch = touches.first collectForce = trackedTouch!.type == .pencil // || view?.traitCollection.forceTouchCapability == .available print("collectForce: \(collectForce)") } if append(touches: touches, event: event) { if isForPencil { state = .began } } } override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { if append(touches: touches, event: event) { if state == .began { state = .changed } } } override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { print("touchesEnded") if append(touches: touches, event: event) { stroke.state = .done state = .ended } } override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) { print("touchesCancelled") if append(touches: touches, event: event) { stroke.state = .cancelled state = .failed } } override func reset() { print("reset") AppState.shared.currentLine = nil trackedTouch = nil super.reset() } }
Jul ’23