Shape built from rounded polygon geometry.

Create instances using the PolygonShape factory functions or predefined companion factories like regularPolygon and star. Instances created with equal parameters compare equal to enable caching resolved outlines across recompositions.

Shapes cache their resolved outline for their most recent layout size. Sharing a single shape instance across composables with differing sizes is supported, but defining separate instances per size avoids cache thrashing when repeatedly redrawing.

Outlines returned by createOutline are shared between callers and must not be mutated.

Summary

Public companion functions

PolygonShape
absoluteRectangle(
    topLeftRounding: PolygonShapeGeometry.CornerRounding,
    topRightRounding: PolygonShapeGeometry.CornerRounding,
    bottomRightRounding: PolygonShapeGeometry.CornerRounding,
    bottomLeftRounding: PolygonShapeGeometry.CornerRounding
)

Creates an absolute rectangular PolygonShape filling the layout bounds, with a separate rounding for each corner.

Cmn
PolygonShape
circle(numVertices: @IntRange(from = 3) Int)

Creates a circular PolygonShape approximated by numVertices rounded vertices.

Cmn
PolygonShape
pill(smoothing: @FloatRange(from = 0.0, to = 1.0) Float)

Creates a pill PolygonShape with rounded ends along the shorter sides of the layout bounds.

Cmn
PolygonShape
pillStar(
    numPoints: @IntRange(from = 2) Int,
    innerRadiusRatio: Float,
    vertexSpacing: Float,
    startLocation: Float,
    outerRounding: PolygonShapeGeometry.CornerRounding,
    innerRounding: PolygonShapeGeometry.CornerRounding
)

Creates a star PolygonShape with vertices placed along a pill outline.

Cmn
PolygonShape

Creates a rectangular PolygonShape filling the layout bounds, with the same rounding at every corner.

Cmn
PolygonShape
rectangle(
    topStartRounding: PolygonShapeGeometry.CornerRounding,
    topEndRounding: PolygonShapeGeometry.CornerRounding,
    bottomEndRounding: PolygonShapeGeometry.CornerRounding,
    bottomStartRounding: PolygonShapeGeometry.CornerRounding
)

Creates a rectangular PolygonShape filling the layout bounds, with a separate rounding for each corner.

Cmn
PolygonShape
regularPolygon(
    numVertices: @IntRange(from = 3) Int,
    rounding: PolygonShapeGeometry.CornerRounding
)

Creates a regular polygon PolygonShape with numVertices vertices, sized to the container's smaller dimension.

Cmn
PolygonShape
star(
    numPoints: @IntRange(from = 2) Int,
    innerRadiusRatio: Float,
    outerRounding: PolygonShapeGeometry.CornerRounding,
    innerRounding: PolygonShapeGeometry.CornerRounding
)

Creates a star PolygonShape with numPoints points on each of the outer and inner radii, sized to the container's smaller dimension.

Cmn

Protected constructors

Cmn

Extension functions

PolygonShape
@RememberInComposition
PolygonShape.scaledToFit(
    contentScale: ContentScale,
    alignment: Alignment
)

Returns a new PolygonShape scaled and aligned into the layout bounds.

Cmn
PolygonShape
@RememberInComposition
PolygonShape.transformed(
    matrix: Matrix,
    contentScale: ContentScale?,
    alignment: Alignment
)

Returns a new PolygonShape with matrix applied to the underlying geometry.

Cmn
PolygonShape
@RememberInComposition
PolygonShape.transformed(
    rotation: Float,
    translation: Offset,
    contentScale: ContentScale?,
    alignment: Alignment
)

Returns a new PolygonShape with rotation and translation applied to the underlying geometry.

Cmn

Inherited functions

From androidx.compose.ui.graphics.Shape
abstract Outline
createOutline(
    size: Size,
    layoutDirection: LayoutDirection,
    density: Density
)

Creates Outline of this shape for the given size.

Cmn

Public companion functions

absoluteRectangle

fun absoluteRectangle(
    topLeftRounding: PolygonShapeGeometry.CornerRounding = CornerRounding.Unrounded,
    topRightRounding: PolygonShapeGeometry.CornerRounding = CornerRounding.Unrounded,
    bottomRightRounding: PolygonShapeGeometry.CornerRounding = CornerRounding.Unrounded,
    bottomLeftRounding: PolygonShapeGeometry.CornerRounding = CornerRounding.Unrounded
): PolygonShape

Creates an absolute rectangular PolygonShape filling the layout bounds, with a separate rounding for each corner.

Corner roundings do not swap with the layout direction.

Parameters
topLeftRounding: PolygonShapeGeometry.CornerRounding = CornerRounding.Unrounded

rounding for the top left corner, resolved against the layout bounds

topRightRounding: PolygonShapeGeometry.CornerRounding = CornerRounding.Unrounded

rounding for the top right corner, resolved the same way

bottomRightRounding: PolygonShapeGeometry.CornerRounding = CornerRounding.Unrounded

rounding for the bottom right corner, resolved the same way

bottomLeftRounding: PolygonShapeGeometry.CornerRounding = CornerRounding.Unrounded

rounding for the bottom left corner, resolved the same way

circle

fun circle(numVertices: @IntRange(from = 3) Int = 8): PolygonShape

Creates a circular PolygonShape approximated by numVertices rounded vertices.

Parameters
numVertices: @IntRange(from = 3) Int = 8

number of vertices used to approximate the circle, at least 3

Throws
IllegalArgumentException

if numVertices is less than 3

pill

fun pill(smoothing: @FloatRange(from = 0.0, to = 1.0) Float = 0.0f): PolygonShape

Creates a pill PolygonShape with rounded ends along the shorter sides of the layout bounds.

Parameters
smoothing: @FloatRange(from = 0.0, to = 1.0) Float = 0.0f

the amount by which the arc is "smoothed" by extending the curve from the circular arc on each endcap to the edge between the endcaps. A value of 0 (no smoothing) indicates that the corner is rounded by only a circular arc.

Throws
IllegalArgumentException

if smoothing is outside the range 0 to 1

pillStar

fun pillStar(
    numPoints: @IntRange(from = 2) Int,
    innerRadiusRatio: Float = 0.5f,
    vertexSpacing: Float = 0.5f,
    startLocation: Float = 0.0f,
    outerRounding: PolygonShapeGeometry.CornerRounding = CornerRounding.Unrounded,
    innerRounding: PolygonShapeGeometry.CornerRounding = outerRounding
): PolygonShape

Creates a star PolygonShape with vertices placed along a pill outline.

A pillStar is like a pill except it has inner and outer radii along its pill-shaped outline, just as a star has inner and outer radii along a circular outline. This produces an elongated star shape commonly used for badges, chips, and decorative containers.

Because vertices curve around the semicircular ends of the pill, outer and inner vertices have different spacing along the curved ends depending on innerRadiusRatio. The vertexSpacing parameter controls how vertices are spaced along those curved ends:

  • vertexSpacing = 0f: Spaces inner vertices equally along the curved ends (outer vertices will be further apart).

  • vertexSpacing = 1f: Spaces outer vertices equally along the curved ends (inner vertices will be closer together).

  • vertexSpacing = 0.5f (default): Uses the average of the inner and outer spacing so both sets of vertices fall symmetrically along the curved ends.

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.PolygonShape
import androidx.compose.foundation.shape.PolygonShapeGeometry.Companion.CornerRounding
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp

// An elongated star outline distributed along a pill container, creating a decorative badge.
val pillStar = remember {
    PolygonShape.pillStar(
        numPoints = 8,
        innerRadiusRatio = 0.6f,
        outerRounding = CornerRounding(percent = 20, smoothing = 0.5f),
    )
}
Box(Modifier.size(width = 140.dp, height = 64.dp).clip(pillStar).background(Color(0xFFE91E63)))
Parameters
numPoints: @IntRange(from = 2) Int

number of points (tips) on the star, at least 2

innerRadiusRatio: Float = 0.5f

ratio of inner radius to outer radius, in the range (0, 1]

vertexSpacing: Float = 0.5f

how vertices on the curved ends are spaced, from 0 (inner vertices spaced evenly) to 1 (outer vertices spaced evenly); 0.5 takes the average

startLocation: Float = 0.0f

where along the perimeter the outline starts, in the range 0 to 1

outerRounding: PolygonShapeGeometry.CornerRounding = CornerRounding.Unrounded

rounding for the outer corners, resolved against the star's outer radius

innerRounding: PolygonShapeGeometry.CornerRounding = outerRounding

rounding for the inner corners, resolved the same way; matches outerRounding when not specified

Throws
IllegalArgumentException

if numPoints is less than 2, or innerRadiusRatio is outside (0, 1], or vertexSpacing or startLocation are outside the range 0 to 1

rectangle

fun rectangle(rounding: PolygonShapeGeometry.CornerRounding): PolygonShape

Creates a rectangular PolygonShape filling the layout bounds, with the same rounding at every corner.

Parameters
rounding: PolygonShapeGeometry.CornerRounding

rounding for all 4 corners, resolved against the layout bounds

rectangle

fun rectangle(
    topStartRounding: PolygonShapeGeometry.CornerRounding = CornerRounding.Unrounded,
    topEndRounding: PolygonShapeGeometry.CornerRounding = CornerRounding.Unrounded,
    bottomEndRounding: PolygonShapeGeometry.CornerRounding = CornerRounding.Unrounded,
    bottomStartRounding: PolygonShapeGeometry.CornerRounding = CornerRounding.Unrounded
): PolygonShape

Creates a rectangular PolygonShape filling the layout bounds, with a separate rounding for each corner.

Corner roundings mirror automatically with the layout direction.

Parameters
topStartRounding: PolygonShapeGeometry.CornerRounding = CornerRounding.Unrounded

rounding for the top start corner, resolved against the layout bounds

topEndRounding: PolygonShapeGeometry.CornerRounding = CornerRounding.Unrounded

rounding for the top end corner, resolved the same way

bottomEndRounding: PolygonShapeGeometry.CornerRounding = CornerRounding.Unrounded

rounding for the bottom end corner, resolved the same way

bottomStartRounding: PolygonShapeGeometry.CornerRounding = CornerRounding.Unrounded

rounding for the bottom start corner, resolved the same way

regularPolygon

fun regularPolygon(
    numVertices: @IntRange(from = 3) Int,
    rounding: PolygonShapeGeometry.CornerRounding = CornerRounding.Unrounded
): PolygonShape

Creates a regular polygon PolygonShape with numVertices vertices, sized to the container's smaller dimension.

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.PolygonShape
import androidx.compose.foundation.shape.PolygonShapeGeometry.Companion.CornerRounding
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp

// A pentagon whose corners round to 20% of its generating radius, so the rounding scales
// proportionally with the shape at any size.
val pentagon = remember {
    PolygonShape.regularPolygon(numVertices = 5, rounding = CornerRounding(percent = 20))
}
Box(Modifier.size(96.dp).clip(pentagon).background(Color(0xFF009688)))
Parameters
numVertices: @IntRange(from = 3) Int

number of vertices, at least 3

rounding: PolygonShapeGeometry.CornerRounding = CornerRounding.Unrounded

rounding applied to every vertex, resolved against the polygon's radius

Throws
IllegalArgumentException

if numVertices is less than 3

star

fun star(
    numPoints: @IntRange(from = 2) Int,
    innerRadiusRatio: Float = 0.5f,
    outerRounding: PolygonShapeGeometry.CornerRounding = CornerRounding.Unrounded,
    innerRounding: PolygonShapeGeometry.CornerRounding = outerRounding
): PolygonShape

Creates a star PolygonShape with numPoints points on each of the outer and inner radii, sized to the container's smaller dimension.

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.PolygonShape
import androidx.compose.foundation.shape.PolygonShapeGeometry.Companion.CornerRounding
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp

// An eight-point star with smoothly rounded outer points.
val star =
    PolygonShape.star(
        numPoints = 8,
        innerRadiusRatio = 0.6f,
        outerRounding = CornerRounding(percent = 15, smoothing = 0.5f),
    )
Box(Modifier.size(96.dp).clip(star).background(Color(0xFFFFC107)))
Parameters
numPoints: @IntRange(from = 2) Int

number of points (tips) on the star, at least 2

innerRadiusRatio: Float = 0.5f

ratio of inner radius to outer radius, in the range (0, 1]

outerRounding: PolygonShapeGeometry.CornerRounding = CornerRounding.Unrounded

rounding for the outer corners, resolved against the star's outer radius

innerRounding: PolygonShapeGeometry.CornerRounding = outerRounding

rounding for the inner corners, resolved the same way; matches outerRounding when not specified

Throws
IllegalArgumentException

if numPoints is less than 2 or innerRadiusRatio is outside the range (0, 1]

Protected constructors

PolygonShape

protected PolygonShape()

Extension functions

PolygonShape.scaledToFit

@RememberInComposition
fun PolygonShape.scaledToFit(
    contentScale: ContentScale = ContentScale.Fit,
    alignment: Alignment = Alignment.Center
): PolygonShape

Returns a new PolygonShape scaled and aligned into the layout bounds.

contentScale selects the scaling policy and alignment positions the scaled geometry:

Measures the resolved geometry to place a shape accurately even when rounding pulls it inside its nominal bounds. Predefined shapes and scope factories are already bounded; scaling is useful after a transformed call or when applying non-default placement policies.

Leaves the receiver untouched and derives a new shape value.

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.PolygonShape
import androidx.compose.foundation.shape.PolygonShapeGeometry.Companion.CornerRounding
import androidx.compose.foundation.shape.scaledToFit
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp

// Inside a wide container the star keeps its aspect ratio and is centered; passing
// ContentScale.FillBounds instead would stretch it to fill the container.
val star = remember {
    PolygonShape.star(
            numPoints = 5,
            innerRadiusRatio = 0.5f,
            outerRounding = CornerRounding(percent = 30),
        )
        .scaledToFit(contentScale = ContentScale.Fit)
}
Box(Modifier.size(width = 160.dp, height = 64.dp).clip(star).background(Color(0xFF9C27B0)))
Parameters
contentScale: ContentScale = ContentScale.Fit

how to scale the resolved geometry into the layout bounds

alignment: Alignment = Alignment.Center

where to place the scaled geometry within the layout bounds

PolygonShape.transformed

@RememberInComposition
fun PolygonShape.transformed(
    matrix: Matrix,
    contentScale: ContentScale? = null,
    alignment: Alignment = Alignment.Center
): PolygonShape

Returns a new PolygonShape with matrix applied to the underlying geometry.

Rotation, scale, and skew act around the resolved geometry's center, changing the shape's orientation and size in place; translation components move the shape as written.

When contentScale is non-null, the transformed geometry is scaled and aligned into the layout container bounds to prevent rotated corners from escaping the container. Pass contentScale = null (the default) to apply only the matrix transformation without scaling, or use scaledToFit to adjust scaling on an existing shape.

This function returns a new PolygonShape and should not be used for continuous animations. To animate rotation or scale on every frame, apply androidx.compose.ui.graphics.graphicsLayer instead to transform the rendered output without rebuilding geometry.

Leaves the receiver untouched and derives a new shape value holding a snapshot of matrix.

Parameters
matrix: Matrix

affine transformation to apply to the geometry

contentScale: ContentScale? = null

optional scaling policy applied after the transformation, or null to skip scaling

alignment: Alignment = Alignment.Center

where to place the scaled geometry within the layout bounds

Throws
IllegalArgumentException

if matrix has perspective components

PolygonShape.transformed

@RememberInComposition
fun PolygonShape.transformed(
    rotation: Float = 0.0f,
    translation: Offset = Offset.Zero,
    contentScale: ContentScale? = null,
    alignment: Alignment = Alignment.Center
): PolygonShape

Returns a new PolygonShape with rotation and translation applied to the underlying geometry.

rotation is applied clockwise in degrees around the geometry's center, and translation moves the shape by the specified horizontal and vertical offsets.

When contentScale is non-null, the transformed geometry is scaled and aligned into the layout container bounds to prevent rotated corners from escaping the container. Pass contentScale = null (the default) to apply only the transformation without scaling, or use scaledToFit to adjust scaling on an existing shape.

This function returns a new PolygonShape and should not be used for continuous animations. To animate rotation or translation on every frame, apply androidx.compose.ui.graphics.graphicsLayer instead to transform the rendered output without rebuilding geometry.

Leaves the receiver untouched and derives a new shape value.

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.PolygonShape
import androidx.compose.foundation.shape.PolygonShapeGeometry.Companion.CornerRounding
import androidx.compose.foundation.shape.transformed
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp

// A square polygon rotated 45 degrees around its center and scaled into the layout bounds in a
// single pass so the rotated diamond stays inscribed without clipping.
val diamond = remember {
    PolygonShape { polygon(numVertices = 4, rounding = CornerRounding(percent = 15)) }
        .transformed(rotation = 45f, contentScale = ContentScale.Fit)
}
Box(Modifier.size(96.dp).clip(diamond).background(Color(0xFFE91E63)))
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.PolygonShape
import androidx.compose.foundation.shape.PolygonShapeGeometry.Companion.CornerRounding
import androidx.compose.foundation.shape.transformed
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp

// Pre-creates the unrotated and rotated badge shape values. The runtime decision toggles
// between shape instances without rebuilding or recomputing geometry on state flips.
val badge = remember {
    PolygonShape.star(
        numPoints = 8,
        innerRadiusRatio = 0.75f,
        outerRounding = CornerRounding(percent = 40),
    )
}
val selectedBadge = remember(badge) { badge.transformed(rotation = 22.5f) }
var selected by remember { mutableStateOf(false) }
val shape = if (selected) selectedBadge else badge
Box(
    Modifier.size(96.dp).clip(shape).background(Color(0xFF00695C)).clickable {
        selected = !selected
    }
)
Parameters
rotation: Float = 0.0f

clockwise rotation in degrees, applied around the geometry center

translation: Offset = Offset.Zero

offset by which to move the shape

contentScale: ContentScale? = null

optional scaling policy applied after the transformation, or null to skip scaling

alignment: Alignment = Alignment.Center

where to place the scaled geometry within the layout bounds