{% setvar book_path %}/reference/androidx/_book.yaml{% endsetvar %} {% include "_shared/_reference-head-tags.html" %}

CanvasKt

public final class CanvasKt


Summary

Public methods

static final @NonNull Canvas

Create a new Canvas instance that targets its drawing commands to the provided ImageBitmap

static final @NonNull NativeCanvas

Return an instance of the native primitive that implements the Canvas interface

static final void
rotate(@NonNull Canvas receiver, float degrees, float pivotX, float pivotY)

Add a rotation (in degrees clockwise) to the current transform at the given pivot point.

static final void
rotateRad(
    @NonNull Canvas receiver,
    float radians,
    float pivotX,
    float pivotY
)

Add a rotation (in radians clockwise) to the current transform at the given pivot point.

static final void
scale(
    @NonNull Canvas receiver,
    float sx,
    float sy,
    float pivotX,
    float pivotY
)

Add an axis-aligned scale to the current transform, scaling by the first argument in the horizontal direction and the second in the vertical direction at the given pivot coordinate.

static final void
withSave(@NonNull Canvas receiver, @NonNull Function0<Unit> block)

Saves a copy of the current transform and clip on the save stack and executes the provided lambda with the current transform applied.

static final void
withSaveLayer(
    @NonNull Canvas receiver,
    @NonNull Rect bounds,
    @NonNull Paint paint,
    @NonNull Function0<Unit> block
)

Saves a copy of the current transform and clip on the save stack, and then creates a new group which subsequent calls will become a part of.

Public methods

Canvas

public static final @NonNull Canvas Canvas(@NonNull ImageBitmap image)

Create a new Canvas instance that targets its drawing commands to the provided ImageBitmap

getNativeCanvas

public static final @NonNull NativeCanvas getNativeCanvas(@NonNull Canvas receiver)

Return an instance of the native primitive that implements the Canvas interface

rotate

public static final void rotate(@NonNull Canvas receiver, float degrees, float pivotX, float pivotY)

Add a rotation (in degrees clockwise) to the current transform at the given pivot point. The pivot coordinate remains unchanged by the rotation transformation

Parameters
float degrees

to rotate clockwise

float pivotX

The x-coord for the pivot point

float pivotY

The y-coord for the pivot point

rotateRad

public static final void rotateRad(
    @NonNull Canvas receiver,
    float radians,
    float pivotX,
    float pivotY
)

Add a rotation (in radians clockwise) to the current transform at the given pivot point. The pivot coordinate remains unchanged by the rotation transformation

Parameters
float pivotX

The x-coord for the pivot point

float pivotY

The y-coord for the pivot point

scale

public static final void scale(
    @NonNull Canvas receiver,
    float sx,
    float sy,
    float pivotX,
    float pivotY
)

Add an axis-aligned scale to the current transform, scaling by the first argument in the horizontal direction and the second in the vertical direction at the given pivot coordinate. The pivot coordinate remains unchanged by the scale transformation.

If sy is unspecified, sx will be used for the scale in both directions.

Parameters
float sx

The amount to scale in X

float sy

The amount to scale in Y

float pivotX

The x-coord for the pivot point

float pivotY

The y-coord for the pivot point

withSave

public static final void withSave(@NonNull Canvas receiver, @NonNull Function0<Unit> block)

Saves a copy of the current transform and clip on the save stack and executes the provided lambda with the current transform applied. Once the lambda has been executed, the transformation is popped from the stack, undoing the transformation.

See also:

Canvas.saveLayer, which does the same thing but additionally also groups the commands

withSaveLayer

public static final void withSaveLayer(
    @NonNull Canvas receiver,
    @NonNull Rect bounds,
    @NonNull Paint paint,
    @NonNull Function0<Unit> block
)

Saves a copy of the current transform and clip on the save stack, and then creates a new group which subsequent calls will become a part of. When the lambda is executed and the save stack is popped, the group will be flattened into a layer and have the given paint's Paint.colorFilter and Paint.blendMode applied.

This lets you create composite effects, for example making a group of drawing commands semi-transparent. Without using Canvas.saveLayer, each part of the group would be painted individually, so where they overlap would be darker than where they do not. By using Canvas.saveLayer to group them together, they can be drawn with an opaque color at first, and then the entire group can be made transparent using the Canvas.saveLayer's paint.

Using saveLayer with clips

When a rectangular clip operation (from Canvas.clipRect) is not axis-aligned with the raster buffer, or when the clip operation is not rectalinear (e.g. because it is a rounded rectangle clip created by Canvas.clipPath), the edge of the clip needs to be anti-aliased.

If two draw calls overlap at the edge of such a clipped region, without using Canvas.saveLayer, the first drawing will be anti-aliased with the background first, and then the second will be anti-aliased with the result of blending the first drawing and the background. On the other hand, if Canvas.saveLayer is used immediately after establishing the clip, the second drawing will cover the first in the layer, and thus the second alone will be anti-aliased with the background when the layer is clipped and composited (when lambda is finished executing).

Performance considerations

Generally speaking, Canvas.saveLayer is relatively expensive.

There are a several different hardware architectures for GPUs (graphics processing units, the hardware that handles graphics), but most of them involve batching commands and reordering them for performance. When layers are used, they cause the rendering pipeline to have to switch render target (from one layer to another). Render target switches can flush the GPU's command buffer, which typically means that optimizations that one could get with larger batching are lost. Render target switches also generate a lot of memory churn because the GPU needs to copy out the current frame buffer contents from the part of memory that's optimized for writing, and then needs to copy it back in once the previous render target (layer) is restored.

See also: