「AWS無料相談会」をオンラインで開催中

[Flutter] ボトムナビゲーションに、カラフルなアイコン画像を”そのまま”表示する方法

[Flutter] ボトムナビゲーションに、カラフルなアイコン画像を”そのまま”表示する方法

本記事は、Flutter開発における小技の紹介です。

対象読者は以下のとおりです。

  • Flutterでアプリを開発している
  • ボトムナビゲーションのボタンの色をカラフルに表示したい

以下の2つの画像をアイコンとして表示させることを考えていきます。

通常の実装だと、以下のようなコードになると思います。

class BottomNavigatorColor extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: Center(child: Text('ボトムナビゲーションアイコン表示テスト')),
      ),
      bottomNavigationBar: BottomNavigationBar(
        selectedItemColor: Colors.black,
        items: [
          BottomNavigationBarItem(
            icon: ImageIcon(AssetImage('images/blue.png'), size: 32),
            label: 'blue',
          ),
          BottomNavigationBarItem(
            icon: ImageIcon(AssetImage('images/red.png'), size: 32),
            label: 'red',
          ),
        ],
      ),
    );
  }
}

表示は以下のとおりになります。

画像がグレーで表示されてしまっていますね。

原因は、ImageIconウェジェットが画像を表示する際に、必ずcolor属性を指定してしまっているところにあります。
以下は、ImageIconウェジェット内のコードの一部抜粋です(コメントで補足情報を追加しています)。

  @override
  Widget build(BuildContext context) {
    ... (略)

    // コンストラクタで設定されるcolor属性の値 または Theme設定の値から色を取得
    Color iconColor = color ?? iconTheme.color;

    // 透明度を設定
    if (iconOpacity != null && iconOpacity != 1.0)
      iconColor = iconColor.withOpacity(iconColor.opacity * iconOpacity);

    return Semantics(
      label: semanticLabel,
      child: Image(
        image: image,
        width: iconSize,
        height: iconSize,
        // 画像の色を設定
        color: iconColor,
        fit: BoxFit.scaleDown,
        alignment: Alignment.center,
        excludeFromSemantics: true,
      ),
    );

コード内のコメントにも記述していますが、Imageウェジェットのcolor属性を設定していますね。カラフルに画像を表示させたい場合は、設定しないようにしたいのですが、ImageIconウェジェットに渡す引数の調整では、解決できません。

そのため、考えられる解決方法として、

ImageIconウェジェットを継承し、画像の色を設定しない新しいウェジェットを定義する ことにします。

新しいウェジェットは、以下のように定義します。

class MyImageIcon extends ImageIcon {
  const MyImageIcon(
    ImageProvider image, {
    Key key,
    double size,
    Color color,
    String semanticLabel,
  }) : super(image,
            key: key, size: size, color: color, semanticLabel: semanticLabel);

  @override
  Widget build(BuildContext context) {
    return Semantics(
      label: semanticLabel,
      child: Image(
        image: image,
        width: size,
        height: size,
        fit: BoxFit.scaleDown,
        alignment: Alignment.center,
        excludeFromSemantics: true,
        // color属性は設定しない
      ),
    );
  }
}

ImageIconからMyImageIconに置き換えると、以下のような表示になります。

画像の色がそのまま表示されるようになりましたね。

ボトムナビゲーションで、カラフルなアイコンを表示する際の助けになれば幸いです。