在 Compose 中旋转 ImageVector

问题描述 投票:0回答:4

我将 material icon 存储在数据类中,如下所示:

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

data class Item(
    val icon: ImageVector
)

val item = Item(Icons.Filled.Send)

该项目稍后会传递到可组合项,并使用

VectorPainter
进行绘制。

如何将

ImageVector
旋转 90 度?理想情况下,这会产生一个
ImageVector
,我仍然可以将其存储在数据类中。

android kotlin android-jetpack-compose android-vectordrawable
4个回答
2
投票

您可以使用

rotate
修饰符:

类似:

Icon(
    Icons.Filled.ArrowDropDown,
    null,
    Modifier.rotate(90f)
)

您可以添加一个条件来实现旋转和不旋转图标。

类似:

@Composable
fun TrailingIcon(expanded: Boolean) {
    Icon(
        Icons.Filled.ArrowDropDown,
        null,
        Modifier.rotate(if (expanded) 90f else 0f)
    )
}

1
投票

正如我从评论中得到的那样,您的 Composable 没有修饰符参数,这不是一个好的设计。每个可组合项即使您不会立即使用它,也应该始终有一个修饰符参数。

https://chrisbanes.me/posts/always-provide-a-modifier/

在过去一年左右的时间里,我看到了很多看起来像的可组合项 很棒,但它们有一个致命的缺陷:它们没有公开修饰符: 签名中的修饰符参数。

如果您不想阅读整篇文章,请阅读这篇博文的 TL;DR 是:

您编写的任何发出布局的可组合项(甚至是一个简单的 Box), 应该有一个修饰符:Modifier 参数,然后在 布局。

即使可组合项没有修饰符参数,您也可以先将旋转参数添加到

Item
数据类

data class Item(
    val icon: ImageVector,
    val rotation: Float
)

然后用

包装没有 Modifier 参数的 Composable
Box(modifier = Modifier.rotate(item.rotation) {
  // Your Composable here
}

imageVector.root.rotation
rotation
公开为不可变参数,您无法更改该参数,也无法公开 IconVector 的路径,如果这是原因,则可以通过矩阵进行旋转。

public val Icons.Filled.Send: ImageVector
    get() {
        if (_send != null) {
            return _send!!
        }
        _send = materialIcon(name = "Filled.Send") {
            materialPath {
                moveTo(2.01f, 21.0f)
                lineTo(23.0f, 12.0f)
                lineTo(2.01f, 3.0f)
                lineTo(2.0f, 10.0f)
                lineToRelative(15.0f, 2.0f)
                lineToRelative(-15.0f, 2.0f)
                close()
            }
        }
        return _send!!
    }

private var _send: ImageVector? = null

0
投票

您可以构建一个旋转的

ImageVector
,从源
ImageVector
复制所有组和路径,并应用所需的旋转参数(与确定旋转中心点的
pivotX
/
pivotY
的正确值相结合)。

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,
    )
}

用法可以如下所示:

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,
)


-3
投票

您可以使用“ImageVector”类提供的“旋转”方法。例如:

data class Item(
    val icon: ImageVector
)
val item = Item(Icons.Filled.Send.rotate(90f))
© www.soinside.com 2019 - 2024. All rights reserved.