Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rotate ImageVector in Compose

I'm storing a material icon in a data class like so:

import androidx.compose.ui.graphics.vector.ImageVector

data class Item(
    val icon: ImageVector
)

val item = Item(Icons.Filled.Send)

The item is later passed to a composable where it's drawn using a VectorPainter.

How do I rotate the ImageVector by 90 degrees? Ideally this would result in an ImageVector that I can still store in the data class.

like image 875
Marsroverr Avatar asked Dec 21 '25 09:12

Marsroverr


1 Answers

You can build a rotated ImageVector copying all the groups and paths from the source ImageVector, and applying required rotation parameter (combined with correct values of pivotX/pivotY that determines the center point of rotation).

fun ImageVector.Companion.copyFrom(
    src: ImageVector,
    rotation: Float = src.root.rotation,
    pivotX: Float = src.root.pivotX,
    pivotY: Float = src.root.pivotY,
) = ImageVector.Builder(
    name = src.name,
    defaultWidth = src.defaultWidth,
    defaultHeight = src.defaultHeight,
    viewportWidth = src.viewportWidth,
    viewportHeight = src.viewportHeight,
    tintColor = src.tintColor,
    tintBlendMode = src.tintBlendMode,
    autoMirror = src.autoMirror,
).addGroup(
    src = src.root,
    rotation = rotation,
    pivotX = pivotX,
    pivotY = pivotY,
).build()

private fun ImageVector.Builder.addNode(node: VectorNode) {
    when (node) {
        is VectorGroup -> addGroup(node)
        is VectorPath -> addPath(node)
    }
}

private fun ImageVector.Builder.addGroup(
    src: VectorGroup,
    rotation: Float = src.rotation,
    pivotX: Float = src.pivotX,
    pivotY: Float = src.pivotY,
) = apply {
    group(
        name = src.name,
        rotate = rotation,
        pivotX = pivotX,
        pivotY = pivotY,
        scaleX = src.scaleX,
        scaleY = src.scaleY,
        translationX = src.translationX,
        translationY = src.translationY,
        clipPathData = src.clipPathData,
    ) {
        src.forEach { addNode(it) }
    }
}

private fun ImageVector.Builder.addPath(src: VectorPath) = apply {
    addPath(
        pathData = src.pathData,
        pathFillType = src.pathFillType,
        name = src.name,
        fill = src.fill,
        fillAlpha = src.fillAlpha,
        stroke = src.stroke,
        strokeAlpha = src.strokeAlpha,
        strokeLineWidth = src.strokeLineWidth,
        strokeLineCap = src.strokeLineCap,
        strokeLineJoin = src.strokeLineJoin,
        strokeLineMiter = src.strokeLineMiter,
    )
}

The usage can look like this:

val icon = ImageVector.vectorResource(R.drawable.ic_smile)
val rotatedIcon = ImageVector.copyFrom(
    src = icon,
    rotation = 90f,
    pivotX = icon.defaultWidth.value / 2,
    pivotY = icon.defaultHeight.value / 2,
)

preview

like image 125
Idolon Avatar answered Dec 23 '25 22:12

Idolon



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!