고급 스타일러스 기능 지원

스타일러스는 사용자가 메모, 스케치, 생산성 앱 작업, 게임 및 엔터테인먼트 앱에서 휴식을 취하고 즐거운 시간을 보낼 때 정확하고 편하게 앱과 상호작용할 수 있도록 지원합니다.

Android와 ChromeOS는 앱에 혁신적인 스타일러스 환경을 구현하기 위한 다양한 API를 제공합니다. MotionEvent 클래스는 스타일러스 압력, 방향, 기울기, 마우스 오버, 손바닥 감지 등 사용자와 화면의 상호작용에 관한 정보를 제공합니다. 지연 시간이 짧은 그래픽과 모션 예측 라이브러리는 스타일러스 화면 렌더링을 개선하여 종이와 펜 같은 자연스러운 환경을 제공합니다.

MotionEvent

MotionEvent 클래스는 화면에 있는 터치 포인터의 위치 및 이동과 같은 사용자 입력 상호작용을 나타냅니다. 스타일러스 입력의 경우 MotionEvent는 압력, 방향, 기울기, 마우스 오버 데이터도 노출합니다.

이벤트 데이터

뷰 기반 앱에서 MotionEvent 데이터에 액세스하려면 onTouchListener를 설정합니다.

Kotlin

val onTouchListener = View.OnTouchListener { view, event ->
  // Process motion event.
}

Java

View.OnTouchListener listener = (view, event) -> {
  // Process motion event.
};

리스너는 시스템에서 MotionEvent 객체를 수신하므로 앱에서 이를 처리할 수 있습니다.

MotionEvent 객체는 UI 이벤트의 다음과 같은 측면과 관련된 데이터를 제공합니다.

  • 작업: 기기와의 물리적 상호작용(화면 터치, 포인터를 화면 표면 위로 이동, 포인터를 화면 표면 위로 가져가기)
  • 포인터: 화면과 상호작용하는 객체 식별자(손가락, 스타일러스, 마우스)
  • 축: 데이터 유형 — x 및 y 좌표, 압력, 기울기, 방향, 마우스 오버(거리)

작업

스타일러스 지원을 구현하려면 사용자가 실행하는 작업을 파악해야 합니다.

MotionEvent는 모션 이벤트를 정의하는 다양한 ACTION 상수를 제공합니다. 스타일러스에 가장 중요한 작업은 다음과 같습니다.

작업 설명
ACTION_DOWN
ACTION_POINTER_DOWN
포인터가 화면에 닿습니다.
ACTION_MOVE 화면에서 포인터가 움직입니다.
ACTION_UP
ACTION_POINTER_UP
포인터가 더 이상 화면에 닿지 않습니다.
ACTION_CANCEL 이전 또는 현재 모션 세트를 취소해야 하는 경우입니다.

앱은 ACTION_DOWN 발생 시 새 획 시작, ACTION_MOVE,로 획 그리기, ACTION_UP 트리거 시 획 완료와 같은 작업을 실행할 수 있습니다.

지정된 포인터의 ACTION_DOWN에서 ACTION_UP에 이르는 MotionEvent 작업 세트를 모션 세트라고 합니다.

포인터

대부분의 화면은 멀티 터치입니다. 시스템은 각 손가락, 스타일러스, 마우스 또는 화면과 상호작용하는 기타 포인팅 객체에 포인터를 할당합니다. 포인터 인덱스를 사용하면 화면을 터치하는 첫 번째 손가락 또는 두 번째 손가락의 위치와 같은 특정 포인터의 축 정보를 가져올 수 있습니다.

포인터 인덱스 범위는 0부터 MotionEvent#pointerCount()에서 반환된 포인터 수에서 1을 뺀 값까지입니다.

포인터의 축 값은 getAxisValue(axis, pointerIndex) 메서드로 액세스할 수 있습니다. 포인터 인덱스가 생략되면 시스템은 첫 번째 포인터인 포인터 0의 값을 반환합니다.

MotionEvent 객체에는 사용 중인 포인터 유형에 관한 정보가 포함됩니다. 포인터 인덱스를 반복하고 getToolType(pointerIndex) 메서드를 호출하여 포인터 유형을 가져올 수 있습니다.

포인터에 관한 자세한 내용은 멀티 터치 동작 처리를 참고하세요.

스타일러스 입력

TOOL_TYPE_STYLUS로 스타일러스 입력을 필터링할 수 있습니다.

Kotlin

val isStylus = TOOL_TYPE_STYLUS == event.getToolType(pointerIndex)

Java

boolean isStylus = TOOL_TYPE_STYLUS == event.getToolType(pointerIndex);

또한 스타일러스는 TOOL_TYPE_ERASER를 사용하여 지우개로 사용되는 것으로 보고할 수 있습니다.

Kotlin

val isEraser = TOOL_TYPE_ERASER == event.getToolType(pointerIndex)

Java

boolean isEraser = TOOL_TYPE_ERASER == event.getToolType(pointerIndex);

스타일러스 축 데이터

ACTION_DOWNACTION_MOVE는 스타일러스에 관한 축 데이터(즉, x 및 y 좌표, 압력, 방향, 기울기, 마우스 오버)를 제공합니다.

이 데이터에 액세스할 수 있도록 MotionEvent API는 getAxisValue(int)를 제공합니다. 여기서 매개변수는 다음 축 식별자 중 하나입니다.

getAxisValue()의 반환 값
AXIS_X 모션 이벤트의 X 좌표입니다.
AXIS_Y 모션 이벤트의 Y 좌표입니다.
AXIS_PRESSURE 터치 스크린 또는 터치패드의 경우 손가락, 스타일러스 또는 기타 포인터로 적용된 압력입니다. 마우스나 트랙볼의 경우 기본 버튼을 누르면 1, 누르지 않으면 0입니다.
AXIS_ORIENTATION 터치 스크린 또는 터치패드의 경우 기기의 수직면을 기준으로 손가락, 스타일러스 또는 기타 포인터의 방향입니다.
AXIS_TILT 라디안으로 표시되는 스타일러스의 기울기 각도입니다.
AXIS_DISTANCE 화면과 스타일러스의 거리입니다.

예를 들어 MotionEvent.getAxisValue(AXIS_X)는 첫 번째 포인터의 x 좌표를 반환합니다.

멀티 터치 동작 처리도 참고하세요.

위치

다음 호출을 사용하여 포인터의 x 및 y 좌표를 가져올 수 있습니다.

x 및 y 좌표가 매핑된 화면에 스타일러스 그리기
그림 1. 스타일러스 포인터의 x 및 y 화면 좌표

압력

다음 호출을 사용하여 포인터 압력을 가져올 수 있습니다.

getAxisValue(AXIS_PRESSURE) 또는 getPressure()(첫 번째 포인터의 경우)

터치 스크린 또는 터치패드의 압력 값은 0(압력 없음)~1 사이의 값이지만, 화면 보정에 따라 더 높은 값이 반환될 수 있습니다.

저압에서 고압의 연속선을 나타내는 스타일러스 획입니다. 왼쪽의 획은 좁고 희미하여 낮은 압력을 나타냅니다. 획이 왼쪽에서 오른쪽으로 가면서 더 넓고 진해져 맨 오른쪽에서는 가장 넓고 진해 최고 압력을 나타냅니다.
그림 2. 압력 표현: 왼쪽은 낮은 압력, 오른쪽은 높은 압력

방향

방향은 스타일러스가 가리키는 방향을 나타냅니다.

포인터 방향은 getAxisValue(AXIS_ORIENTATION) 또는 getOrientation()(첫 번째 포인터의 경우)을 사용하여 가져올 수 있습니다.

스타일러스의 경우 방향은 0~파이(π)(시계 방향) 또는 0~-파이(π)(시계 반대 방향) 사이의 라디안 값으로 반환됩니다.

방향을 사용하면 실제 브러시를 구현할 수 있습니다. 예를 들어 스타일러스가 평면 브러시를 나타내는 경우 평면 브러시의 너비는 스타일러스 방향에 따라 달라집니다.

그림 3. 왼쪽으로 약 -0.57라디안을 가리키는 스타일러스

기울기

기울기는 화면을 기준으로 스타일러스의 경사를 측정합니다.

기울기는 스타일러스의 양의 각도(라디안)를 반환합니다. 여기서 0은 화면에 직각이고 π/2는 표면에 수평합니다.

기울기 각도는 getAxisValue(AXIS_TILT)(첫 번째 포인터의 단축키 없음)를 사용하여 가져올 수 있습니다.

기울기를 사용하면 기울어진 연필로 음영을 흉내 내는 등 실제 도구에 최대한 가깝게 재현할 수 있습니다.

스타일러스가 화면 표면에서 약 40도 기울어졌습니다.
그림 4. 직각에서 약 0.785라디안(45도) 기울어진 스타일러스

마우스 오버

화면과 스타일러스의 거리는 getAxisValue(AXIS_DISTANCE)로 구할 수 있습니다. 이 메서드는 0.0(화면과 접촉하는 값)에서 스타일러스가 화면에서 멀어짐에 따라 더 높은 값으로 값을 반환합니다. 화면과 스타일러스의 촉(포인트) 사이의 마우스 오버 거리는 화면과 스타일러스의 제조업체에 따라 다릅니다. 구현은 다양할 수 있으므로 앱에 중요한 기능의 경우 정확한 값에 의존하지 마세요.

스타일러스 마우스 오버를 사용하면 브러시의 크기를 미리 보거나 버튼이 선택될 것임을 나타낼 수 있습니다.

그림 5. 화면 위에 마우스 오버된 스타일러스. 스타일러스가 화면 표면을 터치하지 않아도 앱이 반응합니다.

참고: Compose는 UI 요소의 상태를 변경하기 위한 수정자 요소 집합을 제공합니다.

  • hoverable: 포인터 들어가기 및 나가기 이벤트를 사용하여 마우스 오버가 가능하도록 구성요소를 구성합니다.
  • indication: 상호작용이 발생할 때 이 구성요소의 시각적 효과를 그립니다.

손바닥 움직임 무시, 탐색, 원치 않는 입력

멀티 터치 화면에서는 사용자가 필기를 할 때 지지를 위해 자연스럽게 손을 화면에 기대는 등 원치 않는 터치를 등록할 수 있습니다. 손바닥 움직임 무시는 이 동작을 감지하고 마지막 MotionEvent 세트를 취소해야 한다고 알리는 메커니즘입니다.

따라서 원치 않는 터치가 화면에서 삭제되고 적절한 사용자 입력이 다시 렌더링될 수 있도록 사용자 입력 기록을 유지해야 합니다.

ACTION_CANCEL 및 FLAG_CANCELED

ACTION_CANCELFLAG_CANCELED는 모두 이전 MotionEvent 세트가 마지막 ACTION_DOWN에서 취소되어야 함을 알리기 위해 설계되었습니다. 따라서 예를 들어 그리기 앱에서 특정 포인터의 마지막 획을 실행취소할 수 있습니다.

ACTION_CANCEL

Android 1.0(API 수준 1)에 추가되었습니다.

ACTION_CANCEL은 이전 모션 이벤트 세트를 취소해야 함을 나타냅니다.

다음 중 하나라도 감지되면 ACTION_CANCEL이 트리거됩니다.

  • 탐색 동작
  • 손바닥 움직임 무시

ACTION_CANCEL이 트리거되면 getPointerId(getActionIndex())로 활성 포인터를 식별해야 합니다. 그런 다음 입력 기록에서 해당 포인터로 만든 획을 삭제하고 장면을 다시 렌더링합니다.

FLAG_CANCELED

Android 13(API 수준 33)에 추가되었습니다.

FLAG_CANCELED는 위로 올라가는 포인터가 의도치 않은 사용자 터치였음을 나타냅니다. 이 플래그는 일반적으로 사용자가 기기를 쥐거나 화면에 손바닥을 놓는 등 실수로 화면을 터치할 때 설정됩니다.

플래그 값에 액세스하는 방법은 다음과 같습니다.

Kotlin

val cancel = (event.flags and FLAG_CANCELED) == FLAG_CANCELED

Java

boolean cancel = (event.getFlags() & FLAG_CANCELED) == FLAG_CANCELED;

플래그가 설정된 경우 이 포인터의 마지막 ACTION_DOWN에서 마지막 MotionEvent 세트를 실행취소해야 합니다.

ACTION_CANCEL과 마찬가지로 포인터는 getPointerId(actionIndex)로 찾을 수 있습니다.

그림 6. 스타일러스 획과 손바닥 터치로 MotionEvent 세트가 생성됩니다. 손바닥 터치가 취소되고 디스플레이가 다시 렌더링됩니다.

전체 화면, 더 넓은 화면, 탐색 동작

앱이 전체 화면이고 가장자리 근처에 실행 가능한 요소(예: 그리기나 메모 앱의 캔버스)가 있는 경우 화면 하단에서 스와이프하여 탐색을 표시하거나 앱을 백그라운드로 이동하면 캔버스에 원치 않는 터치가 발생할 수 있습니다.

그림 7. 앱을 백그라운드로 이동하는 스와이프 동작

동작으로 인해 앱에서 원치 않는 터치가 트리거되지 않도록 하려면 인셋ACTION_CANCEL를 활용하면 됩니다.

위의 손바닥 움직임 무시, 탐색, 원치 않는 입력도 참고하세요.

WindowInsetsControllersetSystemBarsBehavior() 메서드와 BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE를 사용하여 탐색 동작으로 인해 원치 않는 터치 이벤트가 발생하지 않도록 하세요.

Kotlin

// Configure the behavior of the hidden system bars.
windowInsetsController.systemBarsBehavior =
    WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE

Java

// Configure the behavior of the hidden system bars.
windowInsetsController.setSystemBarsBehavior(
    WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
);

인셋 및 동작 관리에 관한 자세한 내용은 다음을 참고하세요.

짧은 지연 시간

지연 시간은 하드웨어, 시스템, 애플리케이션에서 사용자 입력을 처리하고 렌더링하는 데 필요한 시간입니다.

지연 시간 = 하드웨어 및 OS 입력 처리 + 앱 처리 + 시스템 합성 + 하드웨어 렌더링

지연 시간으로 인해 렌더링된 획이 스타일러스 위치보다 뒤처집니다. 렌더링된 획과 스타일러스 위치 사이의 간격이 지연 시간을 나타냅니다.
그림 8. 지연 시간으로 인해 렌더링된 획이 스타일러스 위치보다 뒤처집니다.

지연 시간 소스

  • 터치 스크린(하드웨어)에 스타일러스 등록: 스타일러스와 OS가 등록되고 동기화되도록 통신할 때 초기 무선 연결
  • 터치 샘플링 레이트(하드웨어): 터치 스크린이 포인터가 표면을 터치하는지 확인하는 초당 횟수. 범위는 60~1000Hz입니다.
  • 입력 처리(앱): 사용자 입력에 색상, 그래픽 효과, 변환 적용
  • 그래픽 렌더링(OS + 하드웨어): 버퍼 전환, 하드웨어 처리

지연 시간이 짧은 그래픽

Jetpack 짧은 지연 시간 그래픽 라이브러리를 사용하면 사용자 입력과 화면 렌더링 간의 처리 시간이 단축됩니다.

라이브러리는 다중 버퍼 렌더링을 피하고 전면 버퍼 렌더링 기법(화면에 직접 씀)을 활용하여 처리 시간을 단축합니다.

전면 버퍼 렌더링

전면 버퍼는 화면이 렌더링에 사용하는 메모리입니다. 화면에 직접 그림을 그릴 수 있는 가장 가까운 앱입니다. 지연 시간이 짧은 라이브러리를 사용하면 앱이 전면 버퍼에 직접 렌더링할 수 있습니다. 이렇게 하면 일반적인 다중 버퍼 렌더링이나 이중 버퍼 렌더링(가장 일반적인 사례)에서 발생할 수 있는 버퍼 전환이 방지되어 성능이 개선됩니다.

앱이 화면 버퍼에 쓰고 화면 버퍼에서 읽습니다.
그림 9. 전면 버퍼 렌더링
앱이 화면 버퍼로 전환되는 다중 버퍼에 씁니다. 앱이 화면 버퍼에서 읽습니다.
그림 10. 다중 버퍼 렌더링

전면 버퍼 렌더링은 화면의 작은 영역을 렌더링하는 훌륭한 기법이지만 전체 화면을 새로 고치는 데 사용하도록 설계되지는 않았습니다. 전면 버퍼 렌더링을 사용하면 앱이 디스플레이가 읽고 있는 버퍼로 콘텐츠를 렌더링합니다. 따라서 아티팩트 렌더링이나 테어링이 발생할 수 있습니다(아래 참고).

짧은 지연 시간 라이브러리는 Android 10(API 수준 29) 이상부터 그리고 Android 10(API 수준 29) 이상을 실행하는 ChromeOS 기기에서 사용할 수 있습니다.

종속 항목

짧은 지연 시간 라이브러리는 전면 버퍼 렌더링 구현을 위한 구성요소를 제공합니다. 라이브러리는 앱의 모듈 build.gradle 파일에 종속 항목으로 추가됩니다.

dependencies {
    implementation "androidx.graphics:graphics-core:1.0.0-alpha03"
}

GLFrontBufferRenderer 콜백

짧은 지연 시간 라이브러리에는 다음 메서드를 정의하는 GLFrontBufferRenderer.Callback 인터페이스가 포함됩니다.

짧은 지연 시간 라이브러리는 GLFrontBufferRenderer와 함께 사용하는 데이터 유형에 관해 독단적이지 않습니다.

그러나 라이브러리는 이 데이터를 수백 개의 데이터 포인트 스트림으로 처리합니다. 따라서 메모리 사용량 및 할당을 최적화하도록 데이터를 설계하세요.

콜백

렌더링 콜백을 사용 설정하려면 GLFrontBufferedRenderer.Callback를 구현하고 onDrawFrontBufferedLayer()onDrawDoubleBufferedLayer()를 재정의합니다. GLFrontBufferedRenderer는 콜백을 사용하여 가능한 한 가장 최적화된 방식으로 데이터를 렌더링합니다.

Kotlin

val callback = object: GLFrontBufferedRenderer.Callback<DATA_TYPE> {

   override fun onDrawFrontBufferedLayer(
       eglManager: EGLManager,
       bufferInfo: BufferInfo,
       transform: FloatArray,
       param: DATA_TYPE
   ) {
       // OpenGL for front buffer, short, affecting small area of the screen.
   }

   override fun onDrawMultiDoubleBufferedLayer(
       eglManager: EGLManager,
       bufferInfo: BufferInfo,
       transform: FloatArray,
       params: Collection<DATA_TYPE>
   ) {
       // OpenGL full scene rendering.
   }
}

Java

GLFrontBufferedRenderer.Callback<DATA_TYPE> callbacks =
    new GLFrontBufferedRenderer.Callback<DATA_TYPE>() {
        @Override
        public void onDrawFrontBufferedLayer(@NonNull EGLManager eglManager,
            @NonNull BufferInfo bufferInfo,
            @NonNull float[] transform,
            DATA_TYPE data_type) {
                // OpenGL for front buffer, short, affecting small area of the screen.
        }

    @Override
    public void onDrawDoubleBufferedLayer(@NonNull EGLManager eglManager,
        @NonNull BufferInfo bufferInfo,
        @NonNull float[] transform,
        @NonNull Collection<? extends DATA_TYPE> collection) {
            // OpenGL full scene rendering.
    }
};
GLFrontBufferedRenderer 인스턴스 선언

앞서 만든 SurfaceView 및 콜백을 제공하여 GLFrontBufferedRenderer를 준비합니다. GLFrontBufferedRenderer는 콜백을 사용하여 전면 및 이중 버퍼에 대한 렌더링을 최적화합니다.

Kotlin

var glFrontBufferRenderer = GLFrontBufferedRenderer<DATA_TYPE>(surfaceView, callbacks)

Java

GLFrontBufferedRenderer<DATA_TYPE> glFrontBufferRenderer =
    new GLFrontBufferedRenderer<DATA_TYPE>(surfaceView, callbacks);
렌더링

전면 버퍼 렌더링은 onDrawFrontBufferedLayer() 콜백을 트리거하는 renderFrontBufferedLayer() 메서드를 호출할 때 시작됩니다.

이중 버퍼 렌더링은 onDrawMultiDoubleBufferedLayer() 콜백을 트리거하는 commit() 함수를 호출할 때 다시 시작됩니다.

다음 예에서는 사용자가 화면에 그리기를 시작하고 (ACTION_DOWN) 포인터를 이리저리 이동할 때 (ACTION_MOVE) 프로세스가 전면 버퍼로 렌더링됩니다 (빠른 렌더링). 이 프로세스는 포인터가 화면 표면을 벗어날 때 (ACTION_UP) 이중 버퍼로 렌더링됩니다.

requestUnbufferedDispatch()를 사용하여 입력 시스템이 모션 이벤트를 일괄 처리하지 않고 사용 가능한 상태가 되는 즉시 전달하도록 요청할 수 있습니다.

Kotlin

when (motionEvent.action) {
   MotionEvent.ACTION_DOWN -> {
       // Deliver input events as soon as they arrive.
       view.requestUnbufferedDispatch(motionEvent)
       // Pointer is in contact with the screen.
       glFrontBufferRenderer.renderFrontBufferedLayer(DATA_TYPE)
   }
   MotionEvent.ACTION_MOVE -> {
       // Pointer is moving.
       glFrontBufferRenderer.renderFrontBufferedLayer(DATA_TYPE)
   }
   MotionEvent.ACTION_UP -> {
       // Pointer is not in contact in the screen.
       glFrontBufferRenderer.commit()
   }
   MotionEvent.CANCEL -> {
       // Cancel front buffer; remove last motion set from the screen.
       glFrontBufferRenderer.cancel()
   }
}

Java

switch (motionEvent.getAction()) {
   case MotionEvent.ACTION_DOWN: {
       // Deliver input events as soon as they arrive.
       surfaceView.requestUnbufferedDispatch(motionEvent);

       // Pointer is in contact with the screen.
       glFrontBufferRenderer.renderFrontBufferedLayer(DATA_TYPE);
   }
   break;
   case MotionEvent.ACTION_MOVE: {
       // Pointer is moving.
       glFrontBufferRenderer.renderFrontBufferedLayer(DATA_TYPE);
   }
   break;
   case MotionEvent.ACTION_UP: {
       // Pointer is not in contact in the screen.
       glFrontBufferRenderer.commit();
   }
   break;
   case MotionEvent.ACTION_CANCEL: {
       // Cancel front buffer; remove last motion set from the screen.
       glFrontBufferRenderer.cancel();
   }
   break;
}

렌더링 권장사항 및 금지사항

권장사항

화면의 작은 부분, 필기, 그리기, 스케치

금지사항

전체 화면 업데이트, 화면 이동, 확대/축소. 테어링이 발생할 수 있습니다.

테어링

테어링은 화면 버퍼가 수정되는 동안 동시에 화면을 새로 고치면 발생합니다. 화면의 일부에는 새 데이터가 표시되고 다른 일부에는 이전 데이터가 표시됩니다.

Android 이미지의 상단과 하단이 화면 새로고침 시의 테어링으로 인해 잘못 정렬됩니다.
그림 11. 화면을 새로 고칠 때 상단에서 하단으로 발생한 테어링

모션 예측

Jetpack 모션 예측 라이브러리는 사용자의 획 경로를 추정하고 렌더기에 인위적인 임시 포인트를 제공하여 체감 지연 시간을 줄입니다.

모션 예측 라이브러리는 실제 사용자 입력을 MotionEvent 객체로 가져옵니다. 객체에는 x 및 y 좌표, 압력, 시간에 관한 정보가 포함되어 있으며, 모션 예측기에서 이를 활용하여 향후 MotionEvent 객체를 예측합니다.

예측된 MotionEvent 객체는 추정치일 뿐입니다. 예측된 이벤트는 인지된 지연 시간을 줄일 수 있지만, 예측된 데이터는 수신되면 실제 MotionEvent 데이터로 대체되어야 합니다.

모션 예측 라이브러리는 Android 4.4(API 수준 19) 이상부터 그리고 Android 9(API 수준 28) 이상을 실행하는 ChromeOS 기기에서 사용할 수 있습니다.

지연 시간으로 인해 렌더링된 획이 스타일러스 위치보다 뒤처집니다. 획과 스타일러스 사이의 간격은 예측 포인트로 채워집니다. 남은 간격이 인지된 지연 시간입니다.
그림 12. 모션 예측으로 줄어든 지연 시간

종속 항목

모션 예측 라이브러리는 예측 구현을 제공합니다. 라이브러리는 앱의 모듈 build.gradle 파일에 종속 항목으로 추가됩니다.

dependencies {
    implementation "androidx.input:input-motionprediction:1.0.0-beta01"
}

구현

모션 예측 라이브러리에는 다음 메서드를 정의하는 MotionEventPredictor 인터페이스가 포함되어 있습니다.

  • record(): 사용자 작업의 기록으로 MotionEvent 객체를 저장합니다.
  • predict(): 예측된 MotionEvent를 반환합니다.
MotionEventPredictor의 인스턴스를 선언합니다.

Kotlin

var motionEventPredictor = MotionEventPredictor.newInstance(view)

Java

MotionEventPredictor motionEventPredictor = MotionEventPredictor.newInstance(surfaceView);
예측기에 데이터 제공

Kotlin

motionEventPredictor.record(motionEvent)

Java

motionEventPredictor.record(motionEvent);
예측

Kotlin

when (motionEvent.action) {
   MotionEvent.ACTION_MOVE -> {
       val predictedMotionEvent = motionEventPredictor?.predict()
       if(predictedMotionEvent != null) {
            // use predicted MotionEvent to inject a new artificial point
       }
   }
}

Java

switch (motionEvent.getAction()) {
   case MotionEvent.ACTION_MOVE: {
       MotionEvent predictedMotionEvent = motionEventPredictor.predict();
       if(predictedMotionEvent != null) {
           // use predicted MotionEvent to inject a new artificial point
       }
   }
   break;
}

모션 예측의 권장사항 및 금지사항

권장사항

새로운 예측 포인트가 추가되면 예측 포인트를 삭제합니다.

금지사항

최종 렌더링에는 예측 포인트를 사용하지 않습니다.

메모 작성 앱

ChromeOS를 사용하면 앱에서 일부 메모 작성 작업을 선언할 수 있습니다.

ChromeOS에서 앱을 메모 작성 앱으로 등록하려면 입력 호환성을 참고하세요.

Android에서 앱을 메모 작성으로 등록하려면 메모 앱 만들기를 참고하세요.

Android 14(API 수준 34)에서는 앱이 잠금 화면에서 메모 작성 활동을 시작할 수 있는 ACTION_CREATE_NOTE 인텐트를 도입했습니다.

ML Kit를 통한 디지털 잉크 인식

ML Kit 디지털 잉크 인식을 사용하면 앱이 디지털 표면의 필기 텍스트를 수백 개의 언어로 인식할 수 있습니다. 스케치를 분류할 수도 있습니다.

ML Kit는 Ink 객체를 만드는 Ink.Stroke.Builder 클래스를 제공합니다. 이 객체는 필기 입력을 텍스트로 변환하기 위해 머신러닝 모델에서 처리할 수 있습니다.

모델은 필기 인식 외에도 삭제 및 원과 같은 동작을 인식할 수 있습니다.

자세한 내용은 디지털 잉크 인식을 참고하세요.

추가 리소스

개발자 가이드

Codelab