CanvasStrokeRenderer


public interface CanvasStrokeRenderer


Renders strokes to a Canvas.

Instead of calling the draw methods here directly, it may be simpler to pass an instance of CanvasStrokeRenderer to androidx.ink.rendering.android.view.ViewStrokeRenderer and use it to calculate transform matrix values.

An example of how to use CanvasStrokeRenderer.draw directly:

class MyView {
// Update these according to app business logic, and call `MyView.invalidate()`
val worldToViewTransform = Matrix() // Call e.g. `setScale(2F)` to zoom in 2x
val strokesWithTransforms = mutableMapOf<Stroke, Matrix>()

private val strokeToViewTransform = Matrix() // reusable scratch object
private val renderer = CanvasStrokeRenderer.create()

fun onDraw(canvas: Canvas) {
for ((stroke, strokeToWorldTransform) in strokesWithTransforms) {
// Combine worldToViewTransform (drawing surface being panned/zoomed/rotated) with
// strokeToWorldTransform (stroke itself being moved/scaled/rotated within the drawing
// surface) to get the overall transform of this stroke.
strokeToViewTransform.set(strokeToWorldTransform)
strokeToViewTransform.postConcat(worldToViewTransform)

canvas.withMatrix(strokeToViewTransform) {
// If coordinates of MyView are scaled/rotated from screen coordinates, then those
// scale/rotation values should be multiplied into the strokeToScreenTransform
// argument to renderer.draw.
renderer.draw(canvas, stroke, strokeToViewTransform)
}
}
}
}

In almost all cases, a developer should use an implementation of this interface obtained from CanvasStrokeRenderer.create.

However, some developers may find it helpful to use their own implementation of this interface, possibly to draw other effects to the Canvas, typically delegating to a renderer from CanvasStrokeRenderer.create for part of the custom rendering behavior to have the additional effects add to or modify the standard stroke rendering behavior. Custom CanvasStrokeRenderer implementations are generally less efficient than effects that can be achieved with a custom androidx.ink.brush.BrushFamily. If a custom implementation draws to different screen locations than the standard implementation, for example surrounding a stroke with additional content, then that additional content will not be taken into account in geometry operations like androidx.ink.geometry.Intersection or androidx.ink.geometry.PartitionedMesh.computeCoverage.

If custom rendering is needed during live authoring of in-progress strokes and that custom rendering involves drawing content outside the stroke boundaries, then be sure to override strokeModifiedRegionOutsetPx.

Summary

Public methods

default static final @NonNull CanvasStrokeRenderer

Create a CanvasStrokeRenderer that is appropriate to the device's API version.

default void
draw(
    @NonNull Canvas canvas,
    @NonNull InProgressStroke inProgressStroke,
    @NonNull AffineTransform strokeToScreenTransform
)

Render a single inProgressStroke on the provided canvas.

default void
draw(
    @NonNull Canvas canvas,
    @NonNull InProgressStroke inProgressStroke,
    @NonNull Matrix strokeToScreenTransform
)

Render a single inProgressStroke on the provided canvas.

default void
draw(
    @NonNull Canvas canvas,
    @NonNull Stroke stroke,
    @NonNull AffineTransform strokeToScreenTransform
)

Render a single stroke on the provided canvas.

default void
draw(
    @NonNull Canvas canvas,
    @NonNull Stroke stroke,
    @NonNull Matrix strokeToScreenTransform
)

Render a single stroke on the provided canvas.

default @Px int

The distance beyond a stroke geometry's bounds that rendering might affect.

Public methods

create

Added in 1.0.0-alpha02
default static final @NonNull CanvasStrokeRenderer create()

Create a CanvasStrokeRenderer that is appropriate to the device's API version.

draw

Added in 1.0.0-alpha02
default void draw(
    @NonNull Canvas canvas,
    @NonNull InProgressStroke inProgressStroke,
    @NonNull AffineTransform strokeToScreenTransform
)

Render a single inProgressStroke on the provided canvas. If inProgressStroke has animated textures, then this will use a default animation progress value of zero.

The strokeToScreenTransform should represent the complete transformation from stroke coordinates to the canvas, modulo translation. This transform will not be applied to the canvas in any way, as it may be made up of several individual transforms applied to the canvas during an app’s drawing logic. If this transform is inaccurate, strokes may appear blurry or aliased.

draw

Added in 1.0.0-alpha02
default void draw(
    @NonNull Canvas canvas,
    @NonNull InProgressStroke inProgressStroke,
    @NonNull Matrix strokeToScreenTransform
)

Render a single inProgressStroke on the provided canvas. If inProgressStroke has animated textures, then this will use a default animation progress value of zero.

The strokeToScreenTransform must be affine. It should represent the complete transformation from stroke coordinates to the canvas, modulo translation. This transform will not be applied to the canvas in any way, as it may be made up of several individual transforms applied to the canvas during an app’s drawing logic. If this transform is inaccurate, strokes may appear blurry or aliased.

draw

Added in 1.0.0-alpha02
default void draw(
    @NonNull Canvas canvas,
    @NonNull Stroke stroke,
    @NonNull AffineTransform strokeToScreenTransform
)

Render a single stroke on the provided canvas. If stroke has animated textures, then this will use a default animation progress value of zero.

To avoid needing to calculate and maintain strokeToScreenTransform, consider using androidx.ink.rendering.android.view.ViewStrokeRenderer instead.

The strokeToScreenTransform should represent the complete transformation from stroke coordinates to the screen, modulo translation. This transform will not be applied to the canvas in any way, as it may be made up of several individual transforms applied to the canvas during an app’s drawing logic. If this transform is inaccurate, strokes may appear blurry or aliased.

draw

Added in 1.0.0-alpha02
default void draw(
    @NonNull Canvas canvas,
    @NonNull Stroke stroke,
    @NonNull Matrix strokeToScreenTransform
)

Render a single stroke on the provided canvas. If stroke has animated textures, then this will use a default animation progress value of zero.

To avoid needing to calculate and maintain strokeToScreenTransform, consider using androidx.ink.rendering.android.view.ViewStrokeRenderer instead.

The strokeToScreenTransform must be affine. It should represent the complete transformation from stroke coordinates to the canvas, modulo translation. This transform will not be applied to the canvas in any way, as it may be made up of several individual transforms applied to the canvas during an app’s drawing logic. If this transform is inaccurate, strokes may appear blurry or aliased.

strokeModifiedRegionOutsetPx

Added in 1.0.0-alpha02
default @Px int strokeModifiedRegionOutsetPx()

The distance beyond a stroke geometry's bounds that rendering might affect. This is currently only applicable to in-progress stroke rendering, where the smallest possible region of the screen is redrawn to optimize performance. But with a custom CanvasStrokeRenderer, certain effects like drop shadows or blurs may render beyond the stroke's geometry, and setting a higher value here can ensure that artifacts are not left on screen after an in-progress stroke has moved on from a particular region of the screen. This value should be set to the lowest value that avoids the artifacts, as larger values will be less performant, and effects that rely on larger values will be less compatible with stroke geometry operations.