1

Is there a way to dynamically set an icon value in Jetpack Compose?

Example, instead of:

Icon(Icons.Filled.Print, "print")

I'd like to do:

Icon(Icons.Filled.(iconValue), iconValueName)
Zim
  • 274
  • 4
  • 17
  • what is this iconValue refered to as? – RaBaKa 78 Jan 27 '22 at 04:08
  • @RaBaKa78 It will have the same value as "Print" in string form but can be any icon like "Menu" or "Person". The problem is that icons are set dynamically from the web and I won't know what icon to set in Android until I get the value. – Zim Jan 27 '22 at 04:15

2 Answers2

6

You can use Java reflection. I rely on the fact that each material icon is placed in a separate file, and all of them are declared under androidx.compose.material.icons.filled package.

@Composable
fun IconByName(name: String) {
    val icon: ImageVector? = remember(name) {
        try {
            val cl = Class.forName("androidx.compose.material.icons.filled.${name}Kt")
            val method = cl.declaredMethods.first()
            method.invoke(null, Icons.Filled) as ImageVector
        } catch (_: Throwable) {
            null
        }
    }
    if (icon != null) {
        Icon(icon, "$name icon")
    }
}

You can check out this answer for more details how Kotlin extensions are compiled to Java code.

I would also write a test for this logic using a couple of icons, just in case Compose changes something in future releases - a package name or moving multiple icons together in the same file, although this is unlikely.

Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
  • Just because I could, I tried generating a source file with a `when` entry for every single icon. Generates just fine at about 10k lines, but compiling it crashes the compiler :'). I guess that answers the question why Compose doesn't offer this itself? Oh well, I'll use the reflection at runtime then. – Jorn Aug 28 '23 at 19:04
-1

You can then use a when statement and select appropriate image vector.

when(imageStringFromWeb) {
    is "email" -> {
        Icon(Icons.Filled.Email, null)
    }
    ...
}

Edited to simplfy the code.

mucahid-erdogan
  • 276
  • 2
  • 10
  • Unfortunately, there are over a thousand icons used in Google Material Design. I am currently using net.steamcrafted:materialiconlib:1.1.5 but sometimes it has different names for the icons (Like "Print" is instead named as "Printer") and has not been updated in years. – Zim Jan 27 '22 at 08:46
  • @PhilipDukhov Indeed there is no need. I thought the we get constant string references. When statement will not work this way obviously. I don't know how you can adapt to those changes. – mucahid-erdogan Jan 27 '22 at 09:03