Implementing Coalesced Touch Support in an App

Panther·2021년 8월 1일
0

https://developer.apple.com/documentation/uikit/touches_presses_and_gestures/handling_touches_in_your_view/getting_high-fidelity_input_with_coalesced_touches/implementing_coalesced_touch_support_in_an_app

"Learn how to create a simple app that handles coalesced touches."

통합된 터치를 처리하는 간단한 앱 생성 방법을 알아봅니다.

Overview

Figure 1은 터치를 캡처하고 결과 경로를 화면에 렌더링하는 간단한 드로잉 앱을 보여줍니다. 앱은 UIKit이 알려주는 모든 터치를 추적합니다. 통합된 터치도 포함합니다. 앱은 하나의 터치 지점에서 다음까지 이어지는 라인 세그먼트들을 그리는 것을 통해 경로를 빌드합니다.

Figure 1 Using coalesced touches for drawing

Provide Storage for the Touches

앱의 메인 뷰는 Stroke 객체의 집합을 빌드하기 위한 들어오는 터치 이벤트들을 사용합니다. Listing 1은 Stroke 클래스의 정의를 나타내고 있고, 각 터치 이벤트에 대한 정보를 저장하는 StrokeSample 클래스 또한 보여주고 있습니다.

Listing 1 Storing touch information in the Stroke class

class Stroke {
    var samples = [StrokeSample]()
    func add(sample: StrokeSample) {
        samples.append(sample)
    }
}
 
struct StrokeSample {
    let location: CGPoint
    let coalescedSample: Bool
    init(point: CGPoint, coalesced : Bool = false) {
        location = point
        coalescedSample = coalesced
    }
}

메인 뷰는 StrokeCollection 클래스를 사용해 생성되었던 Stroke 객체의 컬렉션을 유지합니다. 이 클래스의 strokes 속성은 완성된 strokes를 저장하고, activeStroke 속성은 현재 수정되고 있는 stroke 객체를 포함시킵니다. acceptActiveStroke 메소드를 호출하는 것은 활성화된 stroke를 완성된 strokes의 집합으로 이동시킵니다.

Listing 2 Storing user-generated strokes

class StrokeCollection {
    var strokes = [Stroke]()
    var activeStroke: Stroke? = nil
 
    func acceptActiveStroke() {
        if let stroke = activeStroke {
            strokes.append(stroke)
            activeStroke = nil
        }
    }
}

Retrieve the Coalesced Touches

Listing 3은 새 Stroke 객체를 생성하는 메인 드로잉 뷰의 일부분을 보여주고 있습니다. 뷰는 다중 터치를 지원하지 않기 때문에 첫 번째 터치 이벤트만 추적될 필요가 있습니다. touchesBegan(_:with:) 메소드는 새 stroke 객체를 생성하고, 이를 활성화된 stroke로 표시합니다. 새 터치 데이터는 활성화된 stroke에 추가됩니다. 이는 strokestroke 컬렉션에 허용되는 시점인 touchesEnded(_:with:) 메소드가 호출되는 시점까지 계속됩니다. 만약 터치 연쇄가 어떠한 이유로 방해받을 경우 touchesCancelled(_:with:) 메소드는 현재 활성화된 stroke를 포기합니다.

Listing 3 Receiving touches in the main view

class DrawingView : UIView {
   var strokeCollection: StrokeCollection? {
      didSet {
         // If the strokes change, redraw the view's content.
         if oldValue !== strokeCollection {
            setNeedsDisplay()
         }
      }
   }
 
   // Initialization methods...
 
   // Touch Handling methods
   override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
      // Create a new stroke and make it the active stroke.
      let newStroke = Stroke()
      strokeCollection?.activeStroke = newStroke
 
      // The view does not support multitouch, so get the samples
      //  for only the first touch in the event.
      if let coalesced = event?.coalescedTouches(for: touches.first!) {
         addSamples(for: coalesced)
      }
   }
 
   override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
      if let coalesced = event?.coalescedTouches(for: touches.first!) {
         addSamples(for: coalesced)
      }
   }
 
   override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
      // Accept the current stroke and add it to the stroke collection.
      if let coalesced = event?.coalescedTouches(for: touches.first!) {
         addSamples(for: coalesced)
      }
      // Accept the active stroke.
      strokeCollection?.acceptActiveStroke()
   }
 
   override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
      // Clear the last stroke.
      strokeCollection?.activeStroke = nil
   }
 
   // More methods...
}

DrawingView의 터치 입력 메소드는 새 터치들을 활성화된 stroke에 통합시키기 위해 addSamples 메소드(Listing 4에서 볼 수 있는)를 사용합니다. 이 메소드는 각각의 터치 지점마다 새 StrokeSample을 생성하고, 해당 샘플을 활성화된 stroke에 추가시킵니다. 예제는 플래그는 내부적으로 터치를 통합시킵니다. 하지만 터치는 시스템에 의해 알려진 regular 터치와 다르지 않습니다.

Listing 4 Adding touches to the active stroke
func addSamples(for touches: [UITouch]) {
   if let stroke = strokeCollection?.activeStroke {
      // Add all of the touches to the active stroke.
      for touch in touches {
         if touch == touches.last {
            let sample = StrokeSample(point: touch.preciseLocation(in: self))
            stroke.add(sample: sample)
         } else {
            // If the touch is not the last one in the array,
            //  it was a coalesced touch. 
            let sample = StrokeSample(point: touch.preciseLocation(in: self), 
                                  coalesced: true)
            stroke.add(sample: sample)
         }
      } 
      // Update the view.
      self.setNeedsDisplay()
   }
}

Note
애플 펜슬로부터 오는 드로잉 입력을 캡처하려는 경우 더 정확한 터치 정보를 얻기 위해 location(in:) 메소드 대신 preciseLocation(in:) 메소드를 사용할 수 있습니다. preciseLocation(in:) 메소드는 오직 드로잉 관련 입력을 캡처하기 위해서만 사용되어야 합니다. 인터페이스에 대한 일반적인 상호작용은 location(in:) 메소드를 사용해서 터치 위치를 가져올 수 있도록 해야 합니다.

DrawingView 클래스의 남아있는 메소드는 터치 샘플들을 가져오고 이들을 렌더링된 출력으로 바꿔줍니다. 앱의 Clear 버튼은 뷰의 현재 StrokeCollection 객체를 해제하고 새로운 하나를 생성합니다.

0개의 댓글