[Swift/UIKit] Handwriting recognition 필기체 인식 (1)

양재현·2026년 2월 15일

아이패드에서 손글씨(애플펜슬)로 쓴 글씨를 자동으로 텍스트로 변환시켜 주는 기능에 대해 궁금하여 Handwriting recognition에 대해 알아보려고 한다.

Handwriting recognition란?

직역하면 필기체 인식이다.

아이패드에서 애플펜슬로 텍스트필드에 글씨를 작성하면 자동으로 텍스트로 변환해서 입력이 되는데, 이것이 애플에서 지원하는 scribble기능이자 필기체 인식으로 볼 수 있다.

Scribble기능은 텍스트 필드(직접), 커스텀 뷰(간접) 이렇게 크게 2곳에서 작동할 수 있다.

UIScribbleInteraction(직접), UIIndirectScribbleInteraction(간접) 이 각각 그걸 가능하게 해주는 클래스들이다.

UIScribbleInteraction : 텍스트 필드 안에서 직접 손글씨를 써서 scribble기능이 적용되는 것
UIIndirectScribbleInteraction : 다른 커스텀 뷰에서 손글씨를 써서 그게 텍스트 필드 안으로 scribble되는 간접적인 것

이번글에서는 UIScribbleInteraction에 대해 알아보겠다.

UIScribbleInteraction(직접)

역할

1. Scribble 제어 : 사용자가 Apple Pencil로 텍스트 입력창 위에 직접 글씨를 써서 텍스트를 입력하는 'Scribble' 동작을 관리한다.

2. 커스터마이징: 기본적으로 UITextInput을 구현하는 모든 뷰에서 스크리블이 작동하지만, UIScribbleInteraction을 사용하면 특정 위치에서 기능을 끄거나 동작 방식을 세밀하게 조정할 수 있다.


주요 기능

1. 특정 영역 비활성화 : 특정 영역에서 Apple Pencil 입력을 그리기(Drawing) 용도로만 사용해야 할 경우 스크리블을 억제할 수 있다.

2. UI 최적화 : 사용자가 쓰기를 시작할 때 커스텀 플레이스홀더를 숨기거나, 입력창이 이동하는 동안 포커스가 잡히는 것을 지연시킬 수 있다.

3. 필기 감지 : 사용자가 현재 글씨를 쓰고 있는지(isHandlingWriting), 아니면 곧 Apple Pencil 입력을 할 것으로 예상되는지(isPencilInputExpected)를 확인할 수 있다.


주요 델리게이트 메서드 (UIScribbleInteractionDelegate)

1. 스크리블 상호작용 및 제어

func scribbleInteraction(UIScribbleInteraction, shouldBeginAt: CGPoint) -> Bool
func scribbleInteractionShouldDelayFocus(UIScribbleInteraction) -> Bool
  • 특정 좌표에서 스크리블을 시작할지 여부를 결정한다. (false 반환 시 해당 위치 스크리블 불가)
  • 텍스트 입력 뷰에 포커스가 맞춰지는 것을 지연시키도록 지시한다.

2. 스크리블 입력 추적

func scribbleInteractionWillBeginWriting(UIScribbleInteraction)
func scribbleInteractionDidFinishWriting(UIScribbleInteraction)
  • 사용자가 뷰에 입력을 시작하면 델리게이트에게 알린다.
  • Scribble이 마지막 단어를 받아쓰기하고 입력한 후 사용자가 뷰에서 쓰기를 멈췄음을 알린다.

코드예제

import UIKit

class ScribbleViewController: UIViewController {

    let textView = UITextView()
    let customPlaceholderLabel = UILabel()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
        setupScribbleInteraction()
    }

    private func setupUI() {
        view.backgroundColor = .white
        
        // 텍스트 뷰 설정
        textView.frame = CGRect(x: 20, y: 100, width: view.bounds.width - 40, height: 300)
        textView.layer.borderColor = UIColor.systemGray4.cgColor
        textView.layer.borderWidth = 1
        textView.font = .systemFont(ofSize: 18)
        view.addSubview(textView)
        
        // 커스텀 플레이스홀더 설정
        customPlaceholderLabel.text = "여기에 Apple Pencil로 글씨를 써보세요."
        customPlaceholderLabel.textColor = .lightGray
        customPlaceholderLabel.frame = CGRect(x: 25, y: 108, width: 300, height: 20)
        view.addSubview(customPlaceholderLabel)
    }

    // MARK: - 1. Scribble 제어 및 커스터마이징 설정
    private func setupScribbleInteraction() {
        // 특정 위치 기능 제어 및 동작 방식 세밀 조정을 위해 Interaction 추가
        let scribbleInteraction = UIScribbleInteraction(delegate: self)
        textView.addInteraction(scribbleInteraction)
    }
}

// MARK: - UIScribbleInteractionDelegate
extension ScribbleViewController: UIScribbleInteractionDelegate {

    // 1. 특정 영역 비활성화 (스크리블 상호작용 제어)
    func scribbleInteraction(_ interaction: UIScribbleInteraction, shouldBeginAt location: CGPoint) -> Bool {
        // 예: 텍스트 뷰 상단 50pt 영역은 '그리기(Drawing)' 전용 영역으로 간주하여 Scribble 비활성화
        if location.y < 50 {
            print("상단 50pt 영역입니다. 스크리블이 금지됩니다")
            return false // false 반환 시 해당 위치 스크리블 불가
        }
        return true
    }

    // 2. 포커스 지연 (UI 최적화)
    func scribbleInteractionShouldDelayFocus(_ interaction: UIScribbleInteraction) -> Bool {
        // 사용자가 필기를 시작하려고 할 때 텍스트 입력창에 즉각적인 포커스(키보드 올라옴 등)가
        // 잡히는 것을 지연시켜 더 자연스러운 필기 경험을 제공합니다.
        return true
    }

    // 3. 쓰기 시작 추적 (필기 감지)
    func scribbleInteractionWillBeginWriting(_ interaction: UIScribbleInteraction) {
        // 사용자가 쓰기를 시작할 때 커스텀 플레이스홀더를 숨김
        customPlaceholderLabel.isHidden = true
        
        // 현재 상태 확인 (필기 감지)
        print("--- 쓰기 시작 ---")
        print("Apple Pencil 입력 예상됨 (isPencilInputExpected): \(UIScribbleInteraction.isPencilInputExpected)")
        print("현재 글씨를 쓰는 중인가 (isHandlingWriting): \(interaction.isHandlingWriting)")
    }

    // 4. 쓰기 종료 추적 (필기 감지)
    func scribbleInteractionDidFinishWriting(_ interaction: UIScribbleInteraction) {
        // Scribble이 마지막 단어를 받아쓰기하고 입력을 마쳤을 때 호출됨
        print("--- 쓰기 종료 ---")
        
        // 텍스트가 비어있다면 플레이스홀더를 다시 표시
        if textView.text.isEmpty {
            customPlaceholderLabel.isHidden = false
        }
    }
}

영상과 함께보면,

  • 애플펜슬로 쓰기를 시작할때 필기를 감지하여 플레이스 홀더를 숨겨주며 로그들을 찍는 모습을 볼 수있다. (3. scribbleInteractionWillBeginWriting)
  • 쓰기를 멈췄을때는 또 쓰기 종료 로그가 찍힌다.
    (4. scribbleInteractionDidFinishWriting)
  • 또한 텍스트 필드 상단 부분에서 스크리블을 시도하면 금지 로그가 뜨는 것을 볼 수있다. (1. scribbleInteraction)
  • 그리고 포커스를 지연시켜주는 기능까지 구현되있다.
    (2. scribbleInteractionShouldDelayFocus)




다음글에서는 UIIndirectScribbleInteraction에 대해 알아보겠다.

🍎 참고

https://developer.apple.com/documentation/uikit/uiscribbleinteraction

0개의 댓글