InProgressStrokesView


@UiThread
class InProgressStrokesView : FrameLayout


Displays in-progress ink strokes as MotionEvent user inputs are provided to it.

For a Jetpack Compose equivalent which also provides a default input handler, see androidx.ink.authoring.compose.InProgressStrokes instead.

The visual styles of strokes are highly customizable by passing the appropriate Brush to startStroke, but if that declarative style specification is not rich enough and instead some more detailed programmatic logic is necessary, consider using InProgressShapesView instead.

Summary

Public constructors

InProgressStrokesView(
    context: Context,
    attrs: AttributeSet?,
    defStyleAttr: @AttrRes Int
)

Public functions

Unit

Add a listener to be notified when strokes are finished.

Boolean
addToStroke(event: MotionEvent, pointerId: Int, prediction: MotionEvent?)

Add event data for pointerId to the corresponding in-progress stroke, if present.

Unit
addToStroke(
    inputs: StrokeInputBatch,
    strokeId: InProgressStrokeId,
    prediction: StrokeInputBatch
)

Add input data from a StrokeInputBatch to an existing stroke.

Unit
addToStroke(
    event: MotionEvent,
    pointerId: Int,
    strokeId: InProgressStrokeId,
    prediction: MotionEvent?
)

Add input data, from a particular pointer within a MotionEvent, to an existing stroke.

Boolean
cancelStroke(event: MotionEvent, pointerId: Int)

Cancel the corresponding in-progress stroke with event data for pointerId, if present.

Unit

Cancel the building of a stroke.

Unit

Cancel all in-progress strokes.

Unit

Removes all listeners that had previously been added with addFinishedStrokesListener.

Unit

Eagerly initialize rather than waiting for the first stroke to be drawn.

Boolean
finishStroke(event: MotionEvent, pointerId: Int)

Finish the corresponding in-progress stroke with event data for pointerId, if present.

Unit

Complete the building of a stroke, with the last input data coming from a StrokeInput.

Unit
finishStroke(
    event: MotionEvent,
    pointerId: Int,
    strokeId: InProgressStrokeId
)

Complete the building of a stroke, with the last input data coming from a particular pointer of a MotionEvent.

Map<InProgressStrokeIdStroke>

Returns all the finished strokes that are still being rendered by this view, with map iteration order in the z-order that the strokes are being rendered, from back to front.

Boolean

Returns true if there are any in-progress strokes.

Unit

Stop this view from rendering the strokes with the given IDs.

Unit

Removes a listener that had previously been added with addFinishedStrokesListener.

InProgressStrokeId
startStroke(
    input: StrokeInput,
    brush: Brush,
    strokeToViewTransform: Matrix
)

Start building a stroke with the provided input.

InProgressStrokeId
startStroke(
    event: MotionEvent,
    pointerId: Int,
    brush: Brush,
    motionEventToWorldTransform: Matrix,
    strokeToWorldTransform: Matrix
)

Start building a stroke using a particular pointer within a MotionEvent.

Protected functions

open Unit
open Unit

Public properties

CountingIdlingResource?

Allows a test to easily wait until all in-progress strokes are completed and handed off.

Path?

Denote an area of this InProgressStrokesView where no ink should be visible.

Matrix

The transform matrix to convert MotionEvent coordinates, as passed to startStroke, addToStroke, and finishStroke, into coordinates of this InProgressStrokesView for rendering.

TextureBitmapStore

TextureBitmapStore used to create the CanvasStrokeRenderer.

Inherited functions

From android.widget.FrameLayout
From android.view.View
Unit
addFocusables(views: ArrayList<View>, direction: Int)
Unit
Unit
Unit
ViewPropertyAnimator
Unit
Unit
Unit
Boolean
Boolean
awakenScrollBars(startDelay: Int)
Boolean
awakenScrollBars(startDelay: Int, invalidate: Boolean)
Unit
Unit
Unit
Unit
Boolean
open Boolean
open Boolean
open Boolean
Boolean
Boolean
Unit
Unit
Unit
Boolean
Unit
Unit
Unit
Int
Int
Int
Unit
WindowInsets
Int
Int
Int
AccessibilityNodeInfo
open Unit
Unit
Boolean
Boolean
dispatchNestedFling(velocityX: Float, velocityY: Float, consumed: Boolean)
Boolean
dispatchNestedPreFling(velocityX: Float, velocityY: Float)
Boolean
dispatchNestedPrePerformAccessibilityAction(
    action: Int,
    arguments: Bundle?
)
Boolean
dispatchNestedPreScroll(
    dx: Int,
    dy: Int,
    consumed: IntArray?,
    offsetInWindow: IntArray?
)
Boolean
dispatchNestedScroll(
    dxConsumed: Int,
    dyConsumed: Int,
    dxUnconsumed: Int,
    dyUnconsumed: Int,
    offsetInWindow: IntArray?
)
Boolean
Unit
draw(canvas: Canvas)
Unit
OnBackInvokedDispatcher?
T
<T : View> findViewById(id: Int)
T
<T : View> findViewWithTag(tag: Any)
Boolean
View
focusSearch(direction: Int)
Unit
forceHasOverlappingRendering(hasOverlappingRendering: Boolean)
Unit
Unit
generateDisplayHash(
    hashAlgorithm: String,
    bounds: Rect?,
    executor: Executor,
    callback: DisplayHashResultCallback
)
IntArray
Boolean
getClipBounds(outRect: Rect)
Bitmap
Unit
getDrawingRect(outRect: Rect)
ArrayList<View>
getFocusables(direction: Int)
Unit
Boolean
Boolean
getGlobalVisibleRect(r: Rect, globalOffset: Point)
Unit
getHitRect(outRect: Rect)
open Int
@ViewDebug.ExportedProperty(category = "layout", mapping = [@ViewDebug.IntToString(from = 0, to = "RESOLVED_DIRECTION_LTR"), @ViewDebug.IntToString(from = 1, to = "RESOLVED_DIRECTION_RTL")])
getLayoutDirection()
Boolean
Unit
Unit
Unit
ViewParent
open ViewParent
Any
getTag(key: Int)
open Int
@ViewDebug.ExportedProperty(category = "text", mapping = [@ViewDebug.IntToString(from = 0, to = "INHERIT"), @ViewDebug.IntToString(from = 1, to = "GRAVITY"), @ViewDebug.IntToString(from = 2, to = "TEXT_START"), @ViewDebug.IntToString(from = 3, to = "TEXT_END"), @ViewDebug.IntToString(from = 4, to = "CENTER"), @ViewDebug.IntToString(from = 5, to = "VIEW_START"), @ViewDebug.IntToString(from = 6, to = "VIEW_END")])
getTextAlignment()
open Int
@ViewDebug.ExportedProperty(category = "text", mapping = [@ViewDebug.IntToString(from = 0, to = "INHERIT"), @ViewDebug.IntToString(from = 1, to = "FIRST_STRONG"), @ViewDebug.IntToString(from = 2, to = "ANY_RTL"), @ViewDebug.IntToString(from = 3, to = "LTR"), @ViewDebug.IntToString(from = 4, to = "RTL"), @ViewDebug.IntToString(from = 5, to = "LOCALE"), @ViewDebug.IntToString(from = 6, to = "FIRST_STRONG_LTR"), @ViewDebug.IntToString(from = 7, to = "FIRST_STRONG_RTL")])
getTextDirection()
Unit
Boolean
Boolean
Boolean
Boolean
Boolean
Boolean
Boolean
Boolean
Unit
Unit
invalidate(dirty: Rect)
Unit
invalidate(l: Int, t: Int, r: Int, b: Int)
Unit
Unit
open Boolean
open Boolean
open Boolean
open Boolean
Boolean
open View
keyboardNavigationClusterSearch(currentCluster: View, direction: Int)
Unit
measure(widthMeasureSpec: Int, heightMeasureSpec: Int)
Unit
Unit
Unit
Unit
WindowInsets
Unit
Boolean
Boolean
Unit
Unit
InputConnection
Unit
onCreateViewTranslationRequest(
    supportedFormats: IntArray,
    requestsCollector: Consumer<ViewTranslationRequest>
)
Unit
onCreateVirtualViewTranslationRequests(
    virtualIds: LongArray,
    supportedFormats: IntArray,
    requestsCollector: Consumer<ViewTranslationRequest>
)
Unit
Boolean
Unit
onDraw(canvas: Canvas)
Unit
Unit
Boolean
Unit
Unit
Unit
onFocusChanged(
    gainFocus: Boolean,
    direction: Int,
    previouslyFocusedRect: Rect?
)
Boolean
Unit
Boolean
Unit
Unit
Boolean
onKeyDown(keyCode: Int, event: KeyEvent)
Boolean
onKeyLongPress(keyCode: Int, event: KeyEvent)
Boolean
onKeyMultiple(keyCode: Int, repeatCount: Int, event: KeyEvent)
Boolean
onKeyPreIme(keyCode: Int, event: KeyEvent)
Boolean
onKeyShortcut(keyCode: Int, event: KeyEvent)
Boolean
onKeyUp(keyCode: Int, event: KeyEvent)
Unit
onOverScrolled(
    scrollX: Int,
    scrollY: Int,
    clampedX: Boolean,
    clampedY: Boolean
)
Unit
Unit
Unit
Unit
Unit
Unit
Unit
ContentInfo?
Unit
Unit
onRtlPropertiesChanged(layoutDirection: Int)
Parcelable?
Unit
onScreenStateChanged(screenState: Int)
Unit
onScrollCaptureSearch(
    localVisibleRect: Rect,
    windowOffset: Point,
    targets: Consumer<ScrollCaptureTarget>
)
Unit
onScrollChanged(l: Int, t: Int, oldl: Int, oldt: Int)
Boolean
onSetAlpha(alpha: Int)
Unit
onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int)
Unit
Boolean
Boolean
Unit
Unit
Unit
Unit
onVisibilityChanged(changedView: View, visibility: Int)
Unit
onWindowFocusChanged(hasWindowFocus: Boolean)
Unit
Unit
Boolean
overScrollBy(
    deltaX: Int,
    deltaY: Int,
    scrollX: Int,
    scrollY: Int,
    scrollRangeX: Int,
    scrollRangeY: Int,
    maxOverScrollX: Int,
    maxOverScrollY: Int,
    isTouchEvent: Boolean
)
Boolean
performAccessibilityAction(action: Int, arguments: Bundle?)
Boolean
Boolean
Boolean
Boolean
performHapticFeedback(feedbackConstant: Int)
Boolean
Boolean
performHapticFeedback(feedbackConstant: Int, flags: Int)
Boolean
Boolean
ContentInfo?
Unit
playSoundEffect(soundConstant: Int)
Boolean
post(action: Runnable)
Boolean
postDelayed(action: Runnable, delayMillis: Long)
Unit
Unit
postInvalidate(left: Int, top: Int, right: Int, bottom: Int)
Unit
postInvalidateDelayed(delayMilliseconds: Long)
Unit
postInvalidateDelayed(
    delayMilliseconds: Long,
    left: Int,
    top: Int,
    right: Int,
    bottom: Int
)
Unit
Unit
postInvalidateOnAnimation(left: Int, top: Int, right: Int, bottom: Int)
Unit
Unit
postOnAnimationDelayed(action: Runnable, delayMillis: Long)
Unit
Unit
Boolean
Unit
Unit
Unit
Unit
Unit
open Unit

This function is deprecated. Deprecated in Java

Boolean
Boolean
requestFocus(direction: Int)
Boolean
open Unit
Unit
Unit
Boolean
Boolean
requestRectangleOnScreen(rectangle: Rect, immediate: Boolean)
Boolean
requestRectangleOnScreen(rectangle: Rect, immediate: Boolean, source: Int)
Unit
Unit
T
<T : View> requireViewById(id: Int)
Unit
Unit
Unit
saveAttributeDataForStyleable(
    context: Context,
    styleable: IntArray,
    attrs: AttributeSet?,
    t: TypedArray,
    defStyleAttr: Int,
    defStyleRes: Int
)
Unit
Unit
scheduleDrawable(who: Drawable, what: Runnable, when: Long)
Unit
scrollBy(x: Int, y: Int)
Unit
scrollTo(x: Int, y: Int)
Unit
Unit
Unit
setAccessibilityDataSensitive(accessibilityDataSensitive: Int)
Unit
setAllowClickWhenDisabled(clickableWhenDisabled: Boolean)
Unit
Unit
Unit
setAutofillHints(vararg autofillHints: String)
Unit
Unit
Unit
Unit
Unit
setHandwritingBoundsOffsets(
    offsetLeft: Float,
    offsetTop: Float,
    offsetRight: Float,
    offsetBottom: Float
)
Unit
setHasTransientState(hasTransientState: Boolean)
Unit
setIsCredential(isCredential: Boolean)
Unit
setIsHandwritingDelegate(isHandwritingDelegate: Boolean)
Unit
Unit
setLayerType(layerType: Int, paint: Paint?)
Unit
setLeftTopRightBottom(left: Int, top: Int, right: Int, bottom: Int)
Unit
setMeasuredDimension(measuredWidth: Int, measuredHeight: Int)
Unit
Unit
Unit
Unit
Unit
Unit
Unit
Unit
Unit
Unit
Unit
setOnReceiveContentListener(
    mimeTypes: Array<String>?,
    listener: OnReceiveContentListener?
)
Unit
Unit
Unit
Unit
setPadding(left: Int, top: Int, right: Int, bottom: Int)
Unit
setPaddingRelative(start: Int, top: Int, end: Int, bottom: Int)
Unit
Unit
setRenderEffect(renderEffect: RenderEffect?)
Unit
Unit
setScrollIndicators(indicators: Int, mask: Int)
Unit
setTag(key: Int, tag: Any)
Unit
Unit
Unit
setWillNotCacheDrawing(willNotCacheDrawing: Boolean)
Unit
setWillNotDraw(willNotDraw: Boolean)
Boolean
Boolean
ActionMode
ActionMode
Unit
Boolean
startDrag(
    data: ClipData,
    shadowBuilder: View.DragShadowBuilder,
    myLocalState: Any,
    flags: Int
)
Boolean
startDragAndDrop(
    data: ClipData,
    shadowBuilder: View.DragShadowBuilder,
    myLocalState: Any,
    flags: Int
)
Boolean
Unit
open String
Unit
Unit
Unit
Unit
Unit
Boolean
Boolean
Boolean
From android.view.ViewGroup
Unit
Unit
addExtraDataToAccessibilityNodeInfo(
    info: AccessibilityNodeInfo,
    extraDataKey: String,
    arguments: Bundle?
)
Unit
addFocusables(views: ArrayList<View>, direction: Int, focusableMode: Int)
Unit
addKeyboardNavigationClusters(
    views: MutableCollection<View>,
    direction: Int
)
Boolean
Unit
Unit
addView(child: View)
Unit
addView(child: View, index: Int)
Unit
addView(child: View, params: ViewGroup.LayoutParams)
Unit
addView(child: View, index: Int, params: ViewGroup.LayoutParams)
Unit
addView(child: View, width: Int, height: Int)
Boolean
addViewInLayout(child: View, index: Int, params: ViewGroup.LayoutParams)
Boolean
addViewInLayout(
    child: View,
    index: Int,
    params: ViewGroup.LayoutParams,
    preventRequestLayout: Boolean
)
Unit
attachLayoutAnimationParameters(
    child: View,
    params: ViewGroup.LayoutParams,
    index: Int,
    count: Int
)
Unit
attachViewToParent(child: View, index: Int, params: ViewGroup.LayoutParams)
Unit
Boolean
Unit
Unit
childHasTransientStateChanged(
    child: View,
    childHasTransientState: Boolean
)
Unit
Unit
Unit
Unit
Unit
debug(depth: Int)
Unit
Unit
Unit
Unit
detachViewsFromParent(start: Int, count: Int)
WindowInsets
Boolean
Unit
Unit
dispatchCreateViewTranslationRequest(
    viewIds: MutableMap<AutofillIdLongArray>,
    supportedFormats: IntArray,
    capability: TranslationCapability,
    requests: MutableList<ViewTranslationRequest>
)
Unit
Boolean
Unit
Unit
Unit
Unit
Boolean
Boolean
Boolean
Boolean
Boolean
Boolean
Unit
Unit
Unit
Unit
Unit
Unit
dispatchScrollCaptureSearch(
    localVisibleRect: Rect,
    windowOffset: Point,
    targets: Consumer<ScrollCaptureTarget>
)
Unit
Unit
Unit
Unit
Unit
Unit
Boolean
Boolean
Boolean
dispatchUnhandledMove(focused: View, direction: Int)
Unit
dispatchVisibilityChanged(changedView: View, visibility: Int)
Unit
Unit
Unit
WindowInsets
WindowInsetsAnimation.Bounds
Unit
Unit
Boolean
drawChild(canvas: Canvas, child: View, drawingTime: Long)
Unit
Unit
View
OnBackInvokedDispatcher?
Unit
findViewsWithText(
    outViews: ArrayList<View>,
    text: CharSequence,
    flags: Int
)
View
focusSearch(focused: View, direction: Int)
Unit
Boolean
View
getChildAt(index: Int)
Int
getChildDrawingOrder(drawingPosition: Int)
Int
getChildDrawingOrder(childCount: Int, drawingPosition: Int)
Boolean
Boolean
getChildVisibleRect(child: View, r: Rect, offset: Point)
Boolean
Boolean
Int
Unit
invalidateChild(child: View, dirty: Rect)
ViewParent
invalidateChildInParent(location: IntArray, dirty: Rect)
Unit
Unit
layout(l: Int, t: Int, r: Int, b: Int)
Unit
measureChild(
    child: View,
    parentWidthMeasureSpec: Int,
    parentHeightMeasureSpec: Int
)
Unit
measureChildWithMargins(
    child: View,
    parentWidthMeasureSpec: Int,
    widthUsed: Int,
    parentHeightMeasureSpec: Int,
    heightUsed: Int
)
Unit
measureChildren(widthMeasureSpec: Int, heightMeasureSpec: Int)
Unit
notifySubtreeAccessibilityStateChanged(
    child: View,
    source: View,
    changeType: Int
)
Unit
Unit
IntArray
Unit
onDescendantInvalidated(child: View, target: View)
Boolean
Boolean
Boolean
onNestedFling(
    target: View,
    velocityX: Float,
    velocityY: Float,
    consumed: Boolean
)
Boolean
onNestedPreFling(target: View, velocityX: Float, velocityY: Float)
Boolean
onNestedPrePerformAccessibilityAction(
    target: View,
    action: Int,
    args: Bundle?
)
Unit
onNestedPreScroll(target: View, dx: Int, dy: Int, consumed: IntArray)
Unit
onNestedScroll(
    target: View,
    dxConsumed: Int,
    dyConsumed: Int,
    dxUnconsumed: Int,
    dyUnconsumed: Int
)
Unit
onNestedScrollAccepted(child: View, target: View, axes: Int)
Boolean
onRequestFocusInDescendants(direction: Int, previouslyFocusedRect: Rect)
Boolean
PointerIcon
onResolvePointerIcon(event: MotionEvent, pointerIndex: Int)
Boolean
onStartNestedScroll(child: View, target: View, nestedScrollAxes: Int)
Unit
Unit
onViewAdded(child: View)
Unit
Unit
propagateRequestedFrameRate(frameRate: Float, forceOverride: Boolean)
Unit
Unit
Unit
Unit
removeDetachedView(child: View, animate: Boolean)
Unit
Unit
removeViewAt(index: Int)
Unit
Unit
removeViews(start: Int, count: Int)
Unit
removeViewsInLayout(start: Int, count: Int)
Unit
requestChildFocus(child: View, focused: View)
Boolean
requestChildRectangleOnScreen(
    child: View,
    rectangle: Rect,
    immediate: Boolean
)
Unit
Boolean
requestFocus(direction: Int, previouslyFocusedRect: Rect)
Boolean
Unit
Boolean
Unit
Unit
Unit
Unit
Unit
Unit
Boolean
Boolean
showContextMenuForChild(originalView: View, x: Float, y: Float)
ActionMode
startActionModeForChild(
    originalView: View,
    callback: ActionMode.Callback
)
ActionMode
startActionModeForChild(
    originalView: View,
    callback: ActionMode.Callback,
    type: Int
)
Unit
Unit
Unit
Unit
From android.view.ViewParent
Boolean
requestChildRectangleOnScreen(
    child: View,
    rectangle: Rect,
    immediate: Boolean,
    source: Int
)

Inherited properties

From android.widget.FrameLayout
From android.view.View
open View.AccessibilityDelegate
open Int
open AccessibilityNodeProvider
open CharSequence?
open Int
open Int
open String?
open String?
open Float
open Animation
open Matrix?
open IBinder
open MutableMap<IntInt>
open Array<String>?
AutofillId
open Int
open AutofillValue?
open Drawable
open BlendMode?
open ColorStateList?
open PorterDuff.Mode?
open Int
Int
open Float
open Int
open Float
open Rect
Boolean
ContentCaptureSession?
open CharSequence
Int
Context
open ContextMenu.ContextMenuInfo
Boolean
open Display
IntArray
open Bitmap
open Int
open Int
open Long
open Float
open Int
open Boolean
open Boolean
open Int
open Drawable
open Int
open BlendMode?
open ColorStateList?
open PorterDuff.Mode?
open Float
open Handler
open Float
open Float
open Float
open Float
open Int
open Runnable?
Boolean
Int
open Int
open Int
open Drawable?
open Drawable?
open Int
open Int
open Int
open Int
open Boolean
open Boolean
open Boolean
open Boolean
open Boolean
open Boolean
open Boolean
Boolean
open Boolean
open Boolean
open Boolean
open Boolean
open Boolean
open Boolean
Boolean
Boolean
open Boolean
Boolean
open Boolean
open Boolean
open Boolean
open Boolean
open Boolean
open Boolean
open Boolean
open Boolean
Boolean
Boolean
open Boolean
open Boolean
open Boolean
Boolean
open Boolean
open Boolean
open Boolean
open Boolean
open Boolean
open Boolean
open Boolean
open Boolean
open Boolean
Boolean
open Boolean
open Boolean
open Boolean
open Boolean
open Boolean
open Boolean
open Boolean
Boolean
open Boolean
open Boolean
Boolean
open Boolean
open Boolean
open Boolean
open Boolean
open Boolean
open KeyEvent.DispatcherState
open Int
open Int
open Int
open ViewGroup.LayoutParams
Int
open Float
open Int
open Matrix
Int
Int
Int
Int
Int
open Int
open Int
open Int
open Int
open Int
open Int
open Int
open Int
open View.OnFocusChangeListener
open Int
open ViewOutlineProvider
open Int
open Int
open Int
open Int
open Int
open Int
open Int
open Int
final ViewParent
open ViewParent
OutcomeReceiver<GetCredentialResponseGetCredentialException>?
GetCredentialRequest?
open Float
open Float
open PointerIcon
MutableList<Rect>
open Array<String>?
open Float
open Resources
Boolean
Int
open Float
open Int
open AttachedSurfaceControl?
open View
open WindowInsets
open Float
open Float
open Float
open Float
open Float
open Int
open Int
open Int
open Int
open Int
open Int
Int
Int
open Int
open Int
CharSequence?
open StateListAnimator
open Int
open Int
open CharSequence?
open MutableList<Rect>
open Int
open Any
open Int
open Int
open CharSequence?
Int
open Float
open Int
open TouchDelegate
open ArrayList<View>
open Float
open String
open Float
open Float
open Float
open Long
open Int
open Int
open Drawable?
open Drawable?
open Int
open ViewTranslationResponse?
open ViewTreeObserver
open Int
Int
open Int
open WindowId
open WindowInsetsController?
open Int
open IBinder
open Int
open Float
open Float
open Float
From android.view.ViewGroup

Public constructors

InProgressStrokesView

Added in 1.0.0
InProgressStrokesView(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: @AttrRes Int = 0
)

Public functions

addFinishedStrokesListener

Added in 1.0.0
fun addFinishedStrokesListener(listener: InProgressStrokesFinishedListener): Unit

Add a listener to be notified when strokes are finished. These strokes will continue to be rendered within this view until removeFinishedStrokes is called. All of the strokes that have been delivered to listeners but have not yet been removed with removeFinishedStrokes are available through getFinishedStrokes.

addToStroke

Added in 1.0.0
fun addToStroke(
    event: MotionEvent,
    pointerId: Int,
    prediction: MotionEvent? = null
): Boolean

Add event data for pointerId to the corresponding in-progress stroke, if present. The stroke must have been started with an overload of startStroke that accepts a MotionEvent.

Parameters
event: MotionEvent

the next MotionEvent as part of a Stroke's input data, typically an ACTION_MOVE.

pointerId: Int

the index of the relevant pointer in the event. If pointerId does not correspond to an in-progress stroke, this call is ignored.

prediction: MotionEvent? = null

optional predicted MotionEvent containing predicted inputs between event and the time of the next frame, as generated by androidx.input.motionprediction.MotionEventPredictor.predict.

Returns
Boolean

Whether the pointer corresponds to an in-progress stroke.

addToStroke

Added in 1.0.0
fun addToStroke(
    inputs: StrokeInputBatch,
    strokeId: InProgressStrokeId,
    prediction: StrokeInputBatch = ImmutableStrokeInputBatch.EMPTY
): Unit

Add input data from a StrokeInputBatch to an existing stroke. The stroke must have been started with an overload of startStroke that accepts a StrokeInput.

Parameters
inputs: StrokeInputBatch

The next StrokeInputBatch to be added to the stroke.

strokeId: InProgressStrokeId

The InProgressStrokeId of the stroke to be built upon.

prediction: StrokeInputBatch = ImmutableStrokeInputBatch.EMPTY

Predicted StrokeInputBatch containing predicted inputs between inputs and the time of the next frame. This can technically be empty, but it is strongly recommended for it to be non-empty to achieve the best performance.

addToStroke

Added in 1.0.0
fun addToStroke(
    event: MotionEvent,
    pointerId: Int,
    strokeId: InProgressStrokeId,
    prediction: MotionEvent? = null
): Unit

Add input data, from a particular pointer within a MotionEvent, to an existing stroke. The stroke must have been started with an overload of startStroke that accepts a MotionEvent.

Parameters
event: MotionEvent

The next MotionEvent as part of a stroke's input data, typically one with MotionEvent.getActionMasked of MotionEvent.ACTION_MOVE.

pointerId: Int

The identifier of the pointer within event to be used for inking, as determined by MotionEvent.getPointerId and used as an input to MotionEvent.findPointerIndex. Note that this is the ID of the pointer, not its index.

strokeId: InProgressStrokeId

The InProgressStrokeId of the stroke to be built upon.

prediction: MotionEvent? = null

Predicted MotionEvent containing predicted inputs between event and the time of the next frame. This value typically comes from androidx.input.motionprediction.MotionEventPredictor.predict. It is technically optional, but it is strongly recommended to achieve the best performance.

cancelStroke

Added in 1.0.0
fun cancelStroke(event: MotionEvent, pointerId: Int): Boolean

Cancel the corresponding in-progress stroke with event data for pointerId, if present. The stroke must have been started with an overload of startStroke that accepts a MotionEvent.

Parameters
event: MotionEvent

The MotionEvent that led to this cancellation, typically an ACTION_CANCEL.

pointerId: Int

the id of the relevant pointer in the event.

Returns
Boolean

Whether the pointer corresponded to an in-progress stroke.

cancelStroke

Added in 1.0.0
fun cancelStroke(strokeId: InProgressStrokeId, event: MotionEvent? = null): Unit

Cancel the building of a stroke. It will no longer be visible within this InProgressStrokesView, and no completed Stroke object will come through InProgressStrokesFinishedListener.

This is typically done for one of three reasons:

  1. A MotionEvent with MotionEvent.getActionMasked of MotionEvent.ACTION_CANCEL. This tends to be when an entire gesture has been canceled, for example when a parent android.view.View uses android.view.ViewGroup.onInterceptTouchEvent to intercept and handle the gesture itself.

  2. A MotionEvent with MotionEvent.getFlags containing MotionEvent.FLAG_CANCELED. This tends to be when the system has detected an unintentional touch, such as from the user resting their palm on the screen while writing or drawing, after some events from that unintentional pointer have already been delivered.

  3. An app's business logic reinterprets a gesture previously used for inking as something else, and the earlier inking may be seen as unintentional. For example, an app that uses single-pointer gestures for inking and dual-pointer gestures for pan/zoom/rotate will start inking when the first pointer goes down, but when the second pointer goes down it may want to cancel the stroke from the first pointer rather than leave the small ink marks on the screen.

Does nothing if a stroke with the given strokeId is not in progress.

Parameters
strokeId: InProgressStrokeId

The InProgressStrokeId of the stroke to be canceled.

event: MotionEvent? = null

The MotionEvent that led to this cancellation, if applicable.

cancelUnfinishedStrokes

Added in 1.0.0
fun cancelUnfinishedStrokes(): Unit

Cancel all in-progress strokes.

clearFinishedStrokesListeners

Added in 1.0.0
fun clearFinishedStrokesListeners(): Unit

Removes all listeners that had previously been added with addFinishedStrokesListener.

eagerInit

Added in 1.0.0
fun eagerInit(): Unit

Eagerly initialize rather than waiting for the first stroke to be drawn. Since initialization can be somewhat heavyweight, doing this as soon as it's likely for the user to start drawing can prevent initialization from introducing latency to the first stroke.

finishStroke

Added in 1.0.0
fun finishStroke(event: MotionEvent, pointerId: Int): Boolean

Finish the corresponding in-progress stroke with event data for pointerId, if present. The stroke must have been started with an overload of startStroke that accepts a MotionEvent.

Parameters
event: MotionEvent

the last MotionEvent as part of a stroke, typically an ACTION_UP.

pointerId: Int

the id of the relevant pointer in the event. If pointerId does not correspond to an in-progress stroke, this call is ignored.

Returns
Boolean

Whether the pointer corresponded to an in-progress stroke.

finishStroke

Added in 1.0.0
fun finishStroke(input: StrokeInput, strokeId: InProgressStrokeId): Unit

Complete the building of a stroke, with the last input data coming from a StrokeInput. The stroke must have been started with an overload of startStroke that accepts a StrokeInput.

Parameters
input: StrokeInput

The last StrokeInput in the stroke.

strokeId: InProgressStrokeId

The InProgressStrokeId of the stroke to be finished.

finishStroke

Added in 1.0.0
fun finishStroke(
    event: MotionEvent,
    pointerId: Int,
    strokeId: InProgressStrokeId
): Unit

Complete the building of a stroke, with the last input data coming from a particular pointer of a MotionEvent. The stroke must have been started with an overload of startStroke that accepts a MotionEvent.

When the stroke no longer needs to be rendered by this InProgressStrokesView and can instead be rendered anywhere in the android.view.View hierarchy using CanvasStrokeRenderer, the resulting Stroke object will be passed to the InProgressStrokesFinishedListener instances registered with this InProgressStrokesView using addFinishedStrokesListener.

Does nothing if a stroke with the given strokeId is not in progress.

Parameters
event: MotionEvent

The last MotionEvent as part of a stroke's input data, typically one with MotionEvent.getActionMasked of MotionEvent.ACTION_UP or MotionEvent.ACTION_POINTER_UP, but can also be other actions.

pointerId: Int

The identifier of the pointer within event to be used for inking, as determined by MotionEvent.getPointerId and used as an input to MotionEvent.findPointerIndex. Note that this is the ID of the pointer, not its index.

strokeId: InProgressStrokeId

The InProgressStrokeId of the stroke to be finished.

getFinishedStrokes

Added in 1.0.0
fun getFinishedStrokes(): Map<InProgressStrokeIdStroke>

Returns all the finished strokes that are still being rendered by this view, with map iteration order in the z-order that the strokes are being rendered, from back to front. This is the same order that strokes were started with startStroke. The IDs of these strokes should be passed to removeFinishedStrokes when they are handed off to another view.

hasUnfinishedStrokes

Added in 1.0.0
fun hasUnfinishedStrokes(): Boolean

Returns true if there are any in-progress strokes.

removeFinishedStrokes

Added in 1.0.0
fun removeFinishedStrokes(strokeIds: Set<InProgressStrokeId>): Unit

Stop this view from rendering the strokes with the given IDs.

This should be called in the same UI thread run loop (HWUI frame) as when the strokes start being rendered elsewhere in the view hierarchy. This means they are saved in a location where they will be picked up in a view's next call to onDraw, and that view's invalidate method has been called. If these two operations are not done within the same UI thread run loop (usually side by side - see example below), then there will be brief rendering errors - either a visual gap where the stroke is not drawn during a frame, or a double draw where the stroke is drawn twice and translucent strokes appear more opaque than they should.

removeFinishedStrokesListener

Added in 1.0.0
fun removeFinishedStrokesListener(
    listener: InProgressStrokesFinishedListener
): Unit

Removes a listener that had previously been added with addFinishedStrokesListener.

startStroke

Added in 1.0.0
fun startStroke(
    input: StrokeInput,
    brush: Brush,
    strokeToViewTransform: Matrix = IDENTITY_MATRIX
): InProgressStrokeId

Start building a stroke with the provided input. This would typically be followed by many calls to addToStroke, and the sequence would end with a call to either finishStroke or cancelStroke.

In most circumstances, the startStroke overload that accepts a MotionEvent is more convenient. However, this overload using a StrokeInput is available for cases where the input data may not come directly from a MotionEvent, such as receiving events over a network connection. Using this function to start a stroke can only be followed by the StrokeInput variants of addToStroke and finishStroke for the same stroke.

If there is a way to request unbuffered dispatch from the source of the input data used here, equivalent to android.view.View.requestUnbufferedDispatch for unbuffered MotionEvent data, then be sure to request it for optimal performance.

Parameters
input: StrokeInput

The StrokeInput that started a stroke.

brush: Brush

Brush specification for the stroke being started. Note that if stroke coordinate units (the StrokeInput.x and StrokeInput.y fields of input) are scaled to be very different in size than screen pixels, then it is recommended to update the value of Brush.epsilon to reflect that.

strokeToViewTransform: Matrix = IDENTITY_MATRIX

The Matrix that converts stroke coordinates as provided in input into the coordinate space of this InProgressStrokesView for rendering.

Returns
InProgressStrokeId

The InProgressStrokeId of the stroke being built, later used to identify which stroke is being updated with addToStroke or ended with finishStroke or cancelStroke.

startStroke

Added in 1.0.0
fun startStroke(
    event: MotionEvent,
    pointerId: Int,
    brush: Brush,
    motionEventToWorldTransform: Matrix = IDENTITY_MATRIX,
    strokeToWorldTransform: Matrix = IDENTITY_MATRIX
): InProgressStrokeId

Start building a stroke using a particular pointer within a MotionEvent. This would typically be followed by many calls to addToStroke, and the sequence would end with a call to either finishStroke or cancelStroke.

In most circumstances, prefer to use this function over startStroke that accepts a StrokeInput. Using this function to start a stroke must only be followed by the MotionEvent variants of addToStroke and finishStroke for the same stroke.

For optimum performance, it is strongly recommended to call android.view.View.requestUnbufferedDispatch using event and the android.view.View that generated event alongside calling this function. When requested this way, unbuffered dispatch mode will automatically end when the gesture is complete.

Parameters
event: MotionEvent

The first MotionEvent as part of a Stroke's input data, typically one with a MotionEvent.getActionMasked value of MotionEvent.ACTION_DOWN or MotionEvent.ACTION_POINTER_DOWN, but not restricted to those action types.

pointerId: Int

The identifier of the pointer within event to be used for inking, as determined by MotionEvent.getPointerId and used as an input to MotionEvent.findPointerIndex. Note that this is the ID of the pointer, not its index.

brush: Brush

Brush specification for the stroke being started. Note that the overall scaling factor of motionEventToWorldTransform and strokeToWorldTransform combined should be related to the value of Brush.epsilon - in general, the larger the combined motionEventToStrokeTransform scaling factor is, the smaller on screen the stroke units are, so Brush.epsilon should be a larger quantity of stroke units to maintain a similar screen size.

motionEventToWorldTransform: Matrix = IDENTITY_MATRIX

The matrix that transforms event coordinates into the client app's "world" coordinates, which typically is defined by how a client app's document is panned/zoomed/rotated. This defaults to the identity matrix, in which case the world coordinate space is the same as the MotionEvent coordinates, but the caller should pass in their own value reflecting a coordinate system that is independent of the device's pixel density (e.g. scaled by 1 / android.util.DisplayMetrics.density) and any pan/zoom/rotate gestures that have been applied to the "camera" which portrays the "world" on the device screen. This matrix must be invertible.

strokeToWorldTransform: Matrix = IDENTITY_MATRIX

Allows an object-specific (stroke-specific) coordinate space to be defined in relation to the caller's "world" coordinate space. This defaults to the identity matrix, which is typical for many use cases at the time of stroke construction. In typical use cases, stroke coordinates and world coordinates may start to differ from one another after stroke creation as a particular stroke is manipulated within the world, e.g. it may be moved, scaled, or rotated relative to other content within an app's document. This matrix must be invertible.

Returns
InProgressStrokeId

The InProgressStrokeId of the stroke being built, later used to identify which stroke is being updated with addToStroke or ended with finishStroke or cancelStroke. Callers that assume strokes map one-to-one with pointers in a gesture (as is typical) can skip storing this return value and use the overrides of addToStroke, finishStroke, and cancelStroke that just take a MotionEvent and a pointerId.

Protected functions

onAttachedToWindow

protected open fun onAttachedToWindow(): Unit

onDetachedFromWindow

protected open fun onDetachedFromWindow(): Unit

Public properties

inProgressStrokeCounter

Added in 1.0.0
@VisibleForTesting
var inProgressStrokeCounterCountingIdlingResource?

Allows a test to easily wait until all in-progress strokes are completed and handed off. There is no reason to set this in non-test code.

maskPath

Added in 1.0.0
var maskPathPath?

Denote an area of this InProgressStrokesView where no ink should be visible. A value of null indicates that strokes will be visible anywhere they are drawn. This is useful for UI elements that float on top of (in Z order) the drawing surface - without this, a user would be able to draw in-progress ("wet") strokes on top of those UI elements, but then when the stroke is finished, it will appear as a dry stroke underneath of the UI element. If this mask is set to the shape and position of the floating UI element, then the ink will never be rendered in that area, making it appear as if it's being drawn underneath the UI element.

This technique is most convincing when the UI element is opaque. Often there are parts of the UI element that are translucent, such as drop shadows, or anti-aliasing along the edges. The result will look a little different between wet and dry strokes for those cases, but it can be a worthwhile tradeoff compared to the alternative of drawing wet strokes on top of that UI element.

Note that this parameter does not affect the contents of the strokes at all, nor how they appear when drawn in a separate composable after InProgressStrokesFinishedListener.onStrokesFinished is called - just how the strokes appear when they are still in progress in this view.

motionEventToViewTransform

Added in 1.0.0
var motionEventToViewTransformMatrix

The transform matrix to convert MotionEvent coordinates, as passed to startStroke, addToStroke, and finishStroke, into coordinates of this InProgressStrokesView for rendering. Defaults to the identity matrix, for the recommended case where InProgressStrokesView exactly overlays the android.view.View that has the touch listener from which MotionEvent instances are being forwarded.

textureBitmapStore

Added in 1.0.0
var textureBitmapStoreTextureBitmapStore

TextureBitmapStore used to create the CanvasStrokeRenderer.

By default, this is a no-op implementation that does not load any brush textures. The factory functions are called when the renderer is initialized, so if this will be changed to something that does load and store texture images, it must be set before the first call to startStroke or eagerInit.