Flutter
May 5, 2021

Mastering Icon: How does it work from the inside?

In this article we will check out the Icon widget and will talk about a lifehack thanks to which values for an icon can be set dynamically: for example, to fetch it from the server.

This article is a translation of our original article in Ukrainian

The Icon widget

The Flutter's Material Framework contains a widget called Icon. This widget is used to, obviously, display icons in a Flutter app. Its difference from the Image widget lies in the fact the Icon widget is controlled by app's theme, and it integrates with its parental widgets (for example, it changes its color in IconButton widget).

Let's see arguments this widget accepts:

Example of the Icon widget in action

The example above displays an icon from the Material Icons collection. Let's check the arguments:

  • First positional argument: IconData instance. We'll talk about it below
  • Non-positional color argument: Color instance. Used to recolor the icon
  • Non-positional size argument: real number, icon's size in pixels

ImageIcon widget

This widget accepts a raster image for straightforward use of it as an icon:

ImageIcon widget example

Syntax is similar to Icon, except the first argument is an instance of ImageProvider. The ImageProvider object is responsible for retrieving images for other widgets. For example, for the Image widget.

It's likely you'll never ever use ImageProvider directly, but will rely on one of the ready implementations instead:

In this example we use an image from our assets.

Need to mention, color icons are going to be reduced to monochrome ones based on alpha (transparency) channel:

Colored images turn to monochrome under the ImageIcon widget, while semi-transparency is respected

Icons and CupertinoIcons collections

The Icons and CupertinoIcons classes are collections of icons for Material Design and iOS accordingly. Need to mention, the collections are not cross-compatible: if you are developing an app which uses Material icons on Android and Cupertino icons on iOS β€” you will have to set the relation be yourself or, for example, you can use the flutter_platform_widgets library, which provides a limited set of icons with relations set.

The list of all the icons is provided on Material Icons page. Each icon is available in four styles: Regular, Rounded, Sharp, Outline. To use a needed style, you just need to add a corresponding ending:

Different icons styles use

All available Cupertino icons are listed on the library page.

Icons and Themes

All the Material Framework components are depending on the set theme. The theme is being defined in the MaterialApp widget using the ThemeData object in theme property.

You can use the style globally for all the icons in your app using the iconTheme property in ThemeData:

Example of Theme use to set the icon style

Except from this, you can rewrite the theme directly in the widget tree by using the IconTheme widget (also, properties from the theme in MaterialApp stop working under this one):

Example of local theme override

How vector icons work

For vector icons, Flutter uses special icon fonts, the fonts which contain icons in place of characters. So, when you use an Icon widget, Flutter creates something like a Text widget with a specially set font. We'll make sure about this later.

IconData type

IconData is the container for the icon data to be drawn. Instances of this type are stored in the Icons collection: for example, Icons.people is an IconData object. Let's see the constructor of this object:

IconData constructor β€” that's the exact way the icons are stored in Icons and CupertinoIcons collections

First positional argument: integer of a character code which corresponds to an icon

Non-positional fontFamily argument: font name which is used to display the icon

So, we can reintroduce this behavior using the Text widget (\uef85 is the character code of the icon):

Icon alternative which uses Text widget

Furthermore, you can use label name instead of character code:

If you replace '\ue8f5' to 'people', the widget continues to work as before

Need to mention, IconData is a constant constructor, that lets the Dart compiler to exclude unused icons.

Dynamic icons and Material Framework integration

❗ Use the technique described below only if you really need it (to store all the icons on client side and provide a needed icon name dynamically), since this hurts the app size. Instead of using this, you could try ImageIcon together with, for example, NetworkImage.

So, we make a conclusion we can use the Text widget to display the icon by its code or label. Thought, this approach has a huge downside: it doesn't integrate with the Material Framework, since Flutter treats this widget as a usual text, not an icon. So let's create own Icon class which is not constant and accepts an icon name to draw (see end of the article for the implementation).

Use:

DynamicIcon use example

Warning! Due to the fact the constructor is not constant, tree shaking will fail, so the app won't compile. This behavior can be disabled by the --no-tree-shake-icons build flag.

Implementation