https://developer.apple.com/documentation/uikit/pencil_interactions/handling_input_from_apple_pencil
"Learn how to detect and respond to touches from Apple Pencil."
애플 펜슬로부터 발생한 터치를 감지하고 이에 응답하는 방법을 알아봅니다.
UIKit
은 사용자의 손가락으로부터 입력된 터치를 알려주는 방식과 동일한 방식으로 애플 펜슬의 터치를 알려줍니다. 구체적으로 UIKit
은 앱에서 터치의 위치를 포함하고 있는 UITouch
객체를 전달합니다. 그러나 애플 펜슬로부터 기인한 터치 객체는 방위각, 애플 펜슬의 고도, 입력의 압력을 포함하는 추가적인 정보를 포함합니다.
Figure 1 Using stylus information as input
애플 펜슬은 분리된 기기이기 때문에 애플 펜슬이 수집하는 고도, 방위각, 압력에 대한 시간과 이에 해당하는 값이 앱에 알려지는 시간 사이에 딜레이가 있습니다. 결과적으로 UIKit
은 초기에 해당 속성들에 대한 측정된 값을 제공할 것이고, 이후에서야 실제 값을 제공할 것입니다. 만약 애플 펜슬로부터 고도, 방위각, 압력 정보를 사용한다면, 측정된 속성들을 명시적으로 처리해야 합니다.
Note
애플 펜슬이 작업할 수 있는 기기는 240 Hz까지 터치를 알려줄 수 있습니다.UIKit
이 보통 60 Hz 수준에서 알리기 때문에 모든 추가적인 터치들은 마지막 위치를 나타내는 하나의 터치에 통합됩니다. 추가 터치 데이터를 가져오는 방법은 Getting High-Fidelity Input with Coalesced Touches를 살펴보시기 바랍니다.
Getting High-Fidelity Input with Coalesced Touches
https://developer.apple.com/documentation/uikit/touches_presses_and_gestures/handling_touches_in_your_view/getting_high-fidelity_input_with_coalesced_touches
https://velog.io/@panther222128/Getting-High-Fidelity-Input-with-Coalesced-Touches
UIKit
이 속성의 값에 대한 측정만 갖고 있는 경우 상응하는 UITouch
객체의 estimatedPropertiesExpectingUpdates
속성에 플래그를 포함합니다. 터치 이벤트를 처리할 때, 이후에 터치 정보를 업데이트해야 하는 필요가 있는지 결정하기 위해 해당 속성을 확인하시기 바랍니다.
터치 객체가 측정된 속성들을 포함하고 있는 경우 UIKit
은 또한 터치를 이후에 확인할 수 있도록 사용하는 estimationUpdateIndex
속성에 값을 제공합니다. estimationUpdateIndex
속성에서 값을 유지하고 있는 딕셔너리에 키로 사용하시기 바랍니다. 해당 키의 값을 터치 정보를 저장하기 위해 사용하는 app-specific 객체에 설정하시기 바랍니다. UIKit
이 이후 실제 값을 알리게 되면, app-specific 객체를 찾기 위해 인덱스를 사용해야 하고, 측정된 값을 실제 값으로 교체해야 합니다.
Listing 1은 앱의 addSamples
메소드를 나타내고 있으며, 이 메소드는 터치 데이터를 캡처할 수 있는 메소드입니다. 각 터치에 대해 메소드는 터치 정보와 함께 커스텀 StrokeSample
객체를 생성합니다. 만약 터치의 압력 값이 오직 측정된 값이라면, registerForEstimates
메소드는 estimationUpdateIndex
속성에서 값을 키로써 사용하면서 딕셔너리에 샘플을 캐싱합니다.
Listing 1 Tracking touches that need updates
var estimates : [NSNumber : StrokeSample]
func addSamples(for touches: [UITouch]) {
if let stroke = strokeCollection?.activeStroke {
for touch in touches {
if touch == touches.last {
let sample = StrokeSample(point: touch.location(in: self),
forceValue: touch.force)
stroke.add(sample: sample)
registerForEstimates(touch: touch, sample: sample)
} else {
let sample = StrokeSample(point: touch.location(in: self),
forceValue: touch.force, coalesced: true)
stroke.add(sample: sample)
registerForEstimates(touch: touch, sample: sample)
}
}
self.setNeedsDisplay()
}
}
func registerForEstimates(touch : UITouch, sample : StrokeSample) {
if touch.estimatedPropertiesExpectingUpdates.contains(.force) {
estimates[touch.estimationUpdateIndex!] = sample
}
}
UIKit
이 터치에 대한 실제 값을 받으면, UIKit
은 리스폰더 혹은 제스쳐 리코그나이저의 touchesEstimatedPropertiesUpdated(_:)
메소드를 호출합니다. 측정된 데이터를 실제 값으로 제공하기 위해 UIKit
이 제공하는 해당 메소드를 사용하시기 바랍니다.
Listing 2는 Listing 1에서 생성했었던 캐싱된 StrokeSample
객체의 압력 값을 업데이트하는 touchesEstimatedPropertiesUpdated(_:)
메소드의 예시를 보여줍니다. 메소드는 측정 딕셔너리로부터 StrokeSample
객체를 회수하기 위해 estimationUpdateIndex
속성에서 값을 사용합니다. 이후 압력 값을 업데이트 하고, 딕셔너리로부터 샘플을 제거합니다.
Listing 2 Updating estimated values
override func touchesEstimatedPropertiesUpdated(_ touches: Set<UITouch>) {
for touch in touches {
// If the force value is no longer an estimate, update it.
if !touch.estimatedPropertiesExpectingUpdates.contains(.force) {
let index = touch.estimationUpdateIndex!
var sample = estimates[index]
sample?.force = touch.force
// Remove the key and value from the dictionary.
estimates.removeValue(forKey: index)
}
}
}
압력 값이 3D 터치 압력 값에 일관적일 수 있도록 애플 펜슬에 의해 알려진 압력 값을 조정합니다.
https://developer.apple.com/documentation/uikit/pencil_interactions/handling_input_from_apple_pencil/computing_the_perpendicular_force_of_apple_pencil
https://velog.io/@panther222128/Computing-the-Computing-the-Perpendicular-Force-of-Apple-Pencil
뷰의 컨텐트에 터치 처리가 복잡하게 연결되어 있는 경우 뷰 서브클래스에서 직접 터치 이벤트를 사용합니다.
https://developer.apple.com/documentation/uikit/touches_presses_and_gestures/handling_touches_in_your_view
https://velog.io/@panther222128/Handling-Touches-in-Your-View
터치의 압력에 기반해 컨텐트를 조작합니다.
https://developer.apple.com/documentation/uikit/touches_presses_and_gestures/tracking_the_force_of_3d_touch_events
https://velog.io/@panther222128/Tracking-the-Force-of-3D-Touch-Events
화면에서 발생하는 터치의 위치, 크기, 움직음, 압력을 나타내는 객체입니다.
https://developer.apple.com/documentation/uikit/uitouch
https://velog.io/@panther222128/UITouch