To achieve optimal drawing performance, use the[`startStroke()`](https://developer.android.com/reference/kotlin/androidx/ink/authoring/InProgressStrokesView#startStroke(android.view.MotionEvent,kotlin.Int,androidx.ink.brush.Brush,android.graphics.Matrix,android.graphics.Matrix))(),[`addToStroke()`](https://developer.android.com/reference/kotlin/androidx/ink/authoring/InProgressStrokesView#addToStroke(androidx.ink.strokes.StrokeInputBatch,androidx.ink.authoring.InProgressStrokeId,androidx.ink.strokes.StrokeInputBatch))(), and[`finishStroke()`](https://developer.android.com/reference/kotlin/androidx/ink/authoring/InProgressStrokesView#finishStroke(android.view.MotionEvent,kotlin.Int,androidx.ink.authoring.InProgressStrokeId))methods of the[`InProgressStrokesView`](https://developer.android.com/reference/kotlin/androidx/ink/authoring/InProgressStrokesView)class, passing[`MotionEvent`](https://developer.android.com/reference/android/view/MotionEvent)objects as input.

1. **Set up UI component**

   Integrate the[`InProgressStrokesView`](https://developer.android.com/reference/kotlin/androidx/ink/authoring/InProgressStrokesView)into your view hierarchy.

   <br />

       <FrameLayout>

         <ScrollView
           android:id="@+id/my_content"
           android:width="match_parent"
           android:height="match_parent"
           >
           <!-- Your content here. -->
         </ScrollView>

         <androidx.ink.authoring.InProgressStrokesView
           android:id="@+id/in_progress_strokes_view"
           android:width="match_parent"
           android:height="match_parent"
           />

       </FrameLayout>

   <br />

2. **Instantiate InProgressStrokesView**

   <br />

   Within your activity or fragment's \[`onCreate()`\]\[ink-draw-include6\] method, obtain a reference to the[`InProgressStrokesView`](https://developer.android.com/reference/kotlin/androidx/ink/authoring/InProgressStrokesView)and establish a touch listener for managing user input.  

       class MyActivity : View.OnTouchListener {
           private lateinit var contentView: ScrollView
           private lateinit var inProgressStrokesView: InProgressStrokesView
           private lateinit var predictor: MotionEventPredictor

           // ... other variables

           override fun onCreate(savedInstanceState: Bundle?) {
               super.onCreate(savedInstanceState)
             predictor = MotionEventPredictor.newInstance(contentView)
               contentView = findViewById(R.id.my_content)
               contentView.setOnTouchListener(touchListener)
               inProgressStrokesView = findViewById(R.id.in_progress_strokes_view)
           }

           // ... (touchListener implementation)
       }

   <br />

   | **Note:** Employing the[`MotionEventPredictor`](https://developer.android.com/reference/kotlin/androidx/input/motionprediction/MotionEventPredictor)interface improves stroke latency by predicting upcoming touch events. Use`MotionEventPredictor`for optimal performance.
3. **Handle touch events**

   Having established the UI components, you can now initiate drawing based on touch events.

   |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------|
   | **`MotionEvent`action**                                                                                                                                                                              | **`InProgressStrokesView`method**                                                                                                                                                                                                                 | **Description**                             |
   | [`ACTION_DOWN`](https://developer.android.com/reference/android/view/MotionEvent#ACTION_DOWN)                                                                                                        | [`startStroke()`](https://developer.android.com/reference/kotlin/androidx/ink/authoring/InProgressStrokesView#startStroke(android.view.MotionEvent,kotlin.Int,androidx.ink.brush.Brush,android.graphics.Matrix,android.graphics.Matrix))          | Begin stroke rendering                      |
   | [`ACTION_MOVE`](https://developer.android.com/reference/android/view/MotionEvent#ACTION_MOVE)                                                                                                        | [`addToStroke()`](https://developer.android.com/reference/kotlin/androidx/ink/authoring/InProgressStrokesView#addToStroke(androidx.ink.strokes.StrokeInputBatch,androidx.ink.authoring.InProgressStrokeId,androidx.ink.strokes.StrokeInputBatch)) | Continue rendering the stroke               |
   | [`ACTION_UP`](https://developer.android.com/reference/android/view/MotionEvent#ACTION_UP)                                                                                                            | [`finishStroke()`](https://developer.android.com/reference/kotlin/androidx/ink/authoring/InProgressStrokesView#finishStroke(android.view.MotionEvent,kotlin.Int,androidx.ink.authoring.InProgressStrokeId))                                       | Finalize the stroke rendering               |
   | [`ACTION_CANCEL`](https://developer.android.com/reference/android/view/MotionEvent#ACTION_CANCEL)or[`FLAG_CANCELED`](https://developer.android.com/reference/android/view/MotionEvent#FLAG_CANCELED) | [`cancelStroke()`](https://developer.android.com/reference/kotlin/androidx/ink/authoring/InProgressStrokesView#cancelStroke(androidx.ink.authoring.InProgressStrokeId,android.view.MotionEvent))                                                  | Implement palm rejection; cancel the stroke |

   <br />

       class MyActivity : View.OnTouchListener {
         private lateinit var contentView: ScrollView
         private lateinit var inProgressStrokesView: InProgressStrokesView

         private var pointerId = -1
         private var strokeId: InProgressStrokeId? = null
         private lateinit var predictor: MotionEventPredictor

         override fun onCreate(savedInstanceState: Bundle?) {
           super.onCreate(savedInstanceState)

           contentView = findViewById(R.id.my_content)
           predictor = MotionEventPredictor.create(contentView)
           contentView.setOnTouchListener(touchListener)
           inProgressStrokesView = findViewById(R.id.in_progress_strokes_view)
         }

         private val touchListener = { view: View, event: MotionEvent ->
           predictor.record(event)
             when (event.actionMasked) {
               MotionEvent.ACTION_DOWN -> {
                 // First pointer - treat it as inking.
                 view.requestUnbufferedDispatch(event)
                 val pointerIndex = event.actionIndex
                 pointerIdToStrokeId[event.getPointerId(pointerIndex)] =
                   inProgressStrokesView.startStroke(event, pointerId)
                 return true
               }
               MotionEvent.ACTION_POINTER_DOWN -> {
                 val stroke = strokeId ?: return false
                 inProgressStrokesView.cancelStroke(stroke, event)
                 strokeId = null
                 pointerId = -1
                 return false
               }
               MotionEvent.ACTION_MOVE -> {
                 val predictedEvent = predictor.predict()
                 try
                 {
                   for (pointerIndex in 0 until pointerCount) {
                     val strokeId =
                     pointerIdToStrokeId[event.getPointerId(pointerIndex)] ?: continue
                     inProgressStrokesView.addToStroke(event, pointerId, strokeId, predictedEvent)
                   } finally {
                     predictedEvent?.recycle()
                   }
                 }
               }
               MotionEvent.ACTION_UP -> {
                 val pointerIndex = event.actionIndex
                 val strokeId =
                   pointerIdToStrokeId[event.getPointerId(pointerIndex)] ?: return false
                 inProgressStrokesView.finishStroke(event, pointerId, strokeId)
                 return true
               }
               MotionEvent.ACTION_CANCEL -> {
                 val pointerIndex = event.actionIndex
                 val strokeId =
                   pointerIdToStrokeId[event.getPointerId(pointerIndex)] ?: return false
                 inProgressStrokesView.cancelStroke(strokeId, event)
                 return true
               }
             }
           return false
         }
       }

   <br />

4. **Handle finished strokes**

   Upon calling[`finishStroke()`](https://developer.android.com/reference/kotlin/androidx/ink/authoring/InProgressStrokesView#finishStroke(android.view.MotionEvent,kotlin.Int,androidx.ink.authoring.InProgressStrokeId)), the stroke is marked for completion. However, the finalization process isn't instantaneous. The stroke is fully processed and becomes accessible to your application shortly after[`finishStroke()`](https://developer.android.com/reference/kotlin/androidx/ink/authoring/InProgressStrokesView#finishStroke(android.view.MotionEvent,kotlin.Int,androidx.ink.authoring.InProgressStrokeId))is called, specifically when there are no other strokes in progress. This ensures that all drawing operations are concluded before the stroke is handed off to the client as*finished*.

   To retrieve finished strokes, you have two options:
   - Implement the[`InProgressStrokesFinishedListener`](https://developer.android.com/reference/kotlin/androidx/ink/authoring/InProgressStrokesFinishedListener)interface within your activity or[ViewModel](https://developer.android.com/topic/libraries/architecture/viewmodel), and register the listener with the`InProgressStrokesView`with[`addFinishedStrokesListener`](https://developer.android.com/reference/androidx/ink/authoring/InProgressStrokesView#addFinishedStrokesListener(androidx.ink.authoring.InProgressStrokesFinishedListener)).
   - Use the[`getFinishedStrokes()`](https://developer.android.com/reference/kotlin/androidx/ink/authoring/InProgressStrokesView#getFinishedStrokes())method of[`InProgressStrokesView`](https://developer.android.com/reference/kotlin/androidx/ink/authoring/InProgressStrokesView)to obtain all finished strokes directly.

       class MyActivity : ComponentActivity(), InProgressStrokesFinishedListener {
         ...

         private val finishedStrokesState = mutableStateOf(emptySet<Stroke>())

         override fun onCreate(savedInstanceState: Bundle?) {
           ...
           inProgressStrokesView.addFinishedStrokesListener(this)
         }

         // ... (handle touch events)

         @UiThread
         override fun onStrokesFinished(strokes: Map<InProgressStrokeId, Stroke>) {
           finishedStrokesState.value += strokes.values
           inProgressStrokesView.removeFinishedStrokes(strokes.keys)
         }
       }

   <br />

   Once you have retrieved the finished strokes, you can use the[`ViewStrokeRenderer`](https://developer.android.com/reference/kotlin/androidx/ink/rendering/android/view/ViewStrokeRenderer)as a higher-level abstraction built on top of the[`CanvasStrokeRenderer`](https://developer.android.com/reference/kotlin/androidx/ink/rendering/android/canvas/CanvasStrokeRenderer). This can further simplify the rendering process within your view hierarchy.  

       class DrawingView(context: Context) : View(context) {
         private val viewStrokeRenderer = ViewStrokeRenderer(myCanvasStrokeRenderer, this)

         override fun onDraw(canvas: Canvas) {
           viewStrokeRenderer.drawWithStrokes(canvas) { scope ->
             canvas.scale(myZoomLevel)
             canvas.rotate(myRotation)
             canvas.translate(myPanX, myPanY)
             scope.drawStroke(myStroke)
             // Draw other objects including more strokes, apply more transformations, ...
           }
         }
       }

   <br />