Jetpack Compose:类似于内置 `Icons.Default` 的自定义 VectorAsset Icon 对象
Jetpack Compose: Custom VectorAsset Icon object similar to built-in `Icons.Default`
看起来从 res
文件夹中的 Android Vector Resources 加载自定义图标的唯一方法是在 @Composable
函数中使用 vectorResource(R.drawable.myVectorName)
方法。
这很棒,但我喜欢为 Icon(asset: VectorAsset)
class 获取 VectorAssets
的语法,它看起来像 Icon(Icons.Default.Plus)
.
看起来 vectorResource()
方法使用了一个名为 loadVectorResource()
的 内部 方法,以及它用来读取实际 XML 的方法组成矢量资产文件的文件也是内部文件。
我将如何在 Jetpack Compose 中创建类似 MyAppIcons.Default.SomeIcon
的对象?
编辑
所以,我找到了某种解决方案。但是,内置 Icon()
函数的我自己的 extension/overloading 会很好,但我不确定是否有正确的方法来做到这一点。
原来我没有动脑筋。答案很简单。
要点是,Icon()
是一个可组合函数,这意味着当然可以在那里使用vectorResource() .
所以,正确的方法不是什么秘密...就是制作你自己的 MyAppIcon()
组件,调用 vectorResource()
然后 return 一个普通的 Icon()
,比如所以:
正确的方法
@Composable
fun MyAppIcon(
resourceId: Int,
modifier: Modifier = Modifier,
tint: Color = AmbientContentColor.current
) {
Icon(
asset = vectorResource(id = resourceId),
modifier = modifier,
tint = tint
)
}
然后您可以在别处创建对象,如下所示:
object MyAppIcons {
val SomeIcon = R.drawable.someIcon
val AnotherIcon = R.drawable.anotherIcon
}
当你把两者放在一起时,你可以这样使用:
MyAppIcon(MyAppIcons.SomeIcon)
我希望 Google 尽快添加此覆盖,允许我们传入资源 ID。
有一种方法可以使用 Icon(Icons.Default.Plus)
加载资产。您需要进行扩展 属性
val androidx.compose.material.icons.Icons.Filled.FiveG : VectorAsset
get() {
}
但我看不到在可组合函数之外获取 VectorAsset
的方法。
当然你可以这样做
val androidx.compose.material.icons.Icons.Filled.FiveG : VectorAsset
get() {
return Assets.FiveG
}
object Assets {
lateinit var FiveG: VectorAsset
}
@Composable
fun initializeAssets() {
Assets.FiveG = vectorResource(R.drawable.ic_baseline_5g_24)
}
但是具有副作用的可组合项不是一个好主意。所以我在等待有人找到一种方法将 SVG 转换为 VectorAsset
Kotlin class 或在可组合函数之外获取 VectorAsset
对象。
使用 painterResource
API 加载矢量绘图或光栅化资产格式,如 PNG。您不需要知道可绘制对象的类型,只需在 Image
可组合项或 paint
修饰符中使用 painterResource
。
// Files in res/drawable folders. For example:
// - res/drawable-nodpi/ic_logo.xml
// - res/drawable-xxhdpi/ic_logo.png
// In your Compose code
Icon(
painter = painterResource(id = R.drawable.ic_logo),
contentDescription = null // decorative element
)
我走另一条路,从 Jetpack Compose 源代码中提取逻辑,将 XML SVG 路径字符串转换为 ImageVector
。最后我想到了这个:
fun makeIconFromXMLPath(
pathStr: String,
viewportWidth: Float = 24f,
viewportHeight: Float = 24f,
defaultWidth: Dp = 24.dp,
defaultHeight: Dp = 24.dp,
fillColor: Color = Color.White,
): ImageVector {
val fillBrush = SolidColor(fillColor)
val strokeBrush = SolidColor(fillColor)
return ImageVector.Builder(
defaultWidth = defaultWidth,
defaultHeight = defaultHeight,
viewportWidth = viewportWidth,
viewportHeight = viewportHeight,
).run {
addPath(
pathData = addPathNodes(pathStr),
name = "",
fill = fillBrush,
stroke = strokeBrush,
)
build()
}
}
您所要做的就是调用此函数,并将 pathStr
设置为可绘制对象 XML 文件中 android:pathData
的值。这是一个例子:
val AppleIcon by lazy { makeAppleIcon() }
// by Austin Andrews, found on https://materialdesignicons.com/
private fun makeAppleIcon(): ImageVector {
return makeIconFromXMLPath(
pathStr = "M20,10C22,13 17,22 15,22C13,22 13,21 12,21C11,21 11,22 9,22C7,22 2,13 4,10C6,7 9,7 11,8V5C5.38,8.07 4.11,3.78 4.11,3.78C4.11,3.78 6.77,0.19 11,5V3H13V8C15,7 18,7 20,10Z"
)
}
@Preview
@Composable
fun AppleIconPreview() {
Surface {
Icon(AppleIcon, "Apple")
}
}
看起来从 res
文件夹中的 Android Vector Resources 加载自定义图标的唯一方法是在 @Composable
函数中使用 vectorResource(R.drawable.myVectorName)
方法。
这很棒,但我喜欢为 Icon(asset: VectorAsset)
class 获取 VectorAssets
的语法,它看起来像 Icon(Icons.Default.Plus)
.
看起来 vectorResource()
方法使用了一个名为 loadVectorResource()
的 内部 方法,以及它用来读取实际 XML 的方法组成矢量资产文件的文件也是内部文件。
我将如何在 Jetpack Compose 中创建类似 MyAppIcons.Default.SomeIcon
的对象?
编辑
所以,我找到了某种解决方案。但是,内置 Icon()
函数的我自己的 extension/overloading 会很好,但我不确定是否有正确的方法来做到这一点。
原来我没有动脑筋。答案很简单。
要点是,Icon()
是一个可组合函数,这意味着当然可以在那里使用vectorResource() .
所以,正确的方法不是什么秘密...就是制作你自己的 MyAppIcon()
组件,调用 vectorResource()
然后 return 一个普通的 Icon()
,比如所以:
正确的方法
@Composable
fun MyAppIcon(
resourceId: Int,
modifier: Modifier = Modifier,
tint: Color = AmbientContentColor.current
) {
Icon(
asset = vectorResource(id = resourceId),
modifier = modifier,
tint = tint
)
}
然后您可以在别处创建对象,如下所示:
object MyAppIcons {
val SomeIcon = R.drawable.someIcon
val AnotherIcon = R.drawable.anotherIcon
}
当你把两者放在一起时,你可以这样使用:
MyAppIcon(MyAppIcons.SomeIcon)
我希望 Google 尽快添加此覆盖,允许我们传入资源 ID。
有一种方法可以使用 Icon(Icons.Default.Plus)
加载资产。您需要进行扩展 属性
val androidx.compose.material.icons.Icons.Filled.FiveG : VectorAsset
get() {
}
但我看不到在可组合函数之外获取 VectorAsset
的方法。
当然你可以这样做
val androidx.compose.material.icons.Icons.Filled.FiveG : VectorAsset
get() {
return Assets.FiveG
}
object Assets {
lateinit var FiveG: VectorAsset
}
@Composable
fun initializeAssets() {
Assets.FiveG = vectorResource(R.drawable.ic_baseline_5g_24)
}
但是具有副作用的可组合项不是一个好主意。所以我在等待有人找到一种方法将 SVG 转换为 VectorAsset
Kotlin class 或在可组合函数之外获取 VectorAsset
对象。
使用 painterResource
API 加载矢量绘图或光栅化资产格式,如 PNG。您不需要知道可绘制对象的类型,只需在 Image
可组合项或 paint
修饰符中使用 painterResource
。
// Files in res/drawable folders. For example:
// - res/drawable-nodpi/ic_logo.xml
// - res/drawable-xxhdpi/ic_logo.png
// In your Compose code
Icon(
painter = painterResource(id = R.drawable.ic_logo),
contentDescription = null // decorative element
)
我走另一条路,从 Jetpack Compose 源代码中提取逻辑,将 XML SVG 路径字符串转换为 ImageVector
。最后我想到了这个:
fun makeIconFromXMLPath(
pathStr: String,
viewportWidth: Float = 24f,
viewportHeight: Float = 24f,
defaultWidth: Dp = 24.dp,
defaultHeight: Dp = 24.dp,
fillColor: Color = Color.White,
): ImageVector {
val fillBrush = SolidColor(fillColor)
val strokeBrush = SolidColor(fillColor)
return ImageVector.Builder(
defaultWidth = defaultWidth,
defaultHeight = defaultHeight,
viewportWidth = viewportWidth,
viewportHeight = viewportHeight,
).run {
addPath(
pathData = addPathNodes(pathStr),
name = "",
fill = fillBrush,
stroke = strokeBrush,
)
build()
}
}
您所要做的就是调用此函数,并将 pathStr
设置为可绘制对象 XML 文件中 android:pathData
的值。这是一个例子:
val AppleIcon by lazy { makeAppleIcon() }
// by Austin Andrews, found on https://materialdesignicons.com/
private fun makeAppleIcon(): ImageVector {
return makeIconFromXMLPath(
pathStr = "M20,10C22,13 17,22 15,22C13,22 13,21 12,21C11,21 11,22 9,22C7,22 2,13 4,10C6,7 9,7 11,8V5C5.38,8.07 4.11,3.78 4.11,3.78C4.11,3.78 6.77,0.19 11,5V3H13V8C15,7 18,7 20,10Z"
)
}
@Preview
@Composable
fun AppleIconPreview() {
Surface {
Icon(AppleIcon, "Apple")
}
}