Flutter Tips
【Flutter&Dart Tips#2】Listを好きなWidget/クラスに変換する一番簡単な方法

皆様こんにちは! セカンドステップ代表のマサトです。

今回は任意のリスト(List<E>)を任意のウィジェット(List<Widget>)や任意のクラス(List<T>)のリストに変換する方法について解説します。

いきなり結論

Listのmapメソッドを使用します。

//【リスト】.map((e) => 【eを使ってウィジェット/クラスを作成】)).toList()
list.map((e) => Text(e.toString())).toList()

厳密に言うとmapメソッドはIterable<E>に実装されている機能です。

Iterable<T> map<T>(T toElement(E e))

https://api.dart.dev/stable/2.16.2/dart-core/Iterable/map.html

各要素に対して引数toElementで指定したFunctionを実行して、その実行結果TをIterableとして返却します。

Functionは元となるList<E>の一つ一つをeに取り出すので、それを好きなクラスに変換します。例えば、eを文字列変換してTextウィジェットを作成したければ(e) => Text(e.toString())と書きます。

あとは出来あがったIterable<T>をList<T>に変換するために、.toList()を呼び出すだけでOKです。

コード

以下のサンプルコードをご覧ください。

import 'package:flutter/material.dart';

void main() {
  runApp(const MaterialApp(home: MyApp()));
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    //StringのList
    var stringList = <String>["あああ", "いいい"];
    //StringのListをTextウィジェットに変換し、Columnで縦に並べる
    var stringListWidget = Column(
      children: stringList.map((e) => Text(e)).toList(),
    );

    //intのList
    var intList = <int>[123, 456];
    //intのListをTextウィジェットに変換し、Columnで縦に並べる
    var intListWidget = Column(
      children: intList.map((e) => Text(e.toString())).toList(),
    );

    // 自分で作ったクラスのリスト
    // var myClassList = <MyClass>[
    //   MyClass("あああ"),
    //   MyClass("いいい"),
    //   MyClass(123.toString()),
    //   MyClass(456.toString()),
    // ];
    //stringListからMyClassのListを生成
    var myClassList = stringList.map((e) => MyClass("$e to MyClass")).toList();
    //intListからMyClassのIterableを生成
    //*addAllを使用する際は、toList()を使用せずにIterableのままでもOK
    myClassList
        .addAll(intList.map((e) => MyClass("${e.toString()} to MyClass")));

    //① クラスのフィールドにアクセスし、取得したデータをこちらでWidgetに加工する場合
    //MyClassのListをTextに変換し、Columnで縦に並べる
    var myClassTextList = Column(
      children: myClassList.map((e) => Text("${e.myData} to Text")).toList(),
    );
    //②-a クラスに特定のWidgetの生成を任せる場合(ListTile)
    //MyClassのListをListTileに変換し、Columnで縦に並べる
    var myClassListTileList = Column(
      children: myClassList.map((e) => e.buildListTile()).toList(),
    );
    //②-b クラスに特定のWidgetの生成を任せる場合(Button)
    //MyClassのListをButtonに変換し、Columnで縦に並べる
    var myClassButtonList = Column(
      children: myClassList.map((e) => e.buildButton()).toList(),
    );
    //②-c クラスに特定のWidgetの生成を任せる場合(Buttonとそのアクションを指定)
    //MyClassのListをButtonに変換し、Columnで縦に並べる
    var myClassButtonWithActionList = Column(
      children: myClassList
          .map((e) => e.buildButtonWithAction(
              () => print("${e.myData} pressed (from MyApp)")))
          .toList(),
    );

    //もちろん、任意の計算を行うint->intも可能です(以下は50を加算して、さらにTextに変換)
    var taxIncluded = Column(
        children: <int>[100, 200, 300]
            .map((e) => Text("int -> int ${e + 50}"))
            .toList());

    return Scaffold(
      body: SafeArea(
        child: SingleChildScrollView(
          child: Column(
            children: [
              stringListWidget,
              intListWidget,
              myClassTextList,
              myClassListTileList,
              myClassButtonList,
              myClassButtonWithActionList,
              taxIncluded,
            ],
          ),
        ),
      ),
    );
  }
}

class MyClass {
  String myData;
  MyClass(this.myData);

  //myDataをListTile化するメソッド
  Widget buildListTile() {
    return ListTile(
      title: Text("$myData to ListTile"),
      onTap: () => print("$myData tapped"),
    );
  }

  //myDataをButton化するメソッド
  Widget buildButton() {
    return buildButtonWithAction(() => print("$myData pressed"));
  }

  //myDataをButton化するメソッド(Buttonの動作を指定するパターン)
  Widget buildButtonWithAction(VoidCallback action) {
    return OutlinedButton(
      onPressed: action,
      child: Text("$myData to OutlinedButton"),
    );
  }
}

動作確認(CodePen)

右上の「EDIT ON CODEPEN」でフルスクリーンに拡大できます!

See the Pen Untitled by Masato (@2ndstepnet) on CodePen.

動作確認(DartPad)

色々改造して実験してみてください! コツが掴めると非常に便利な機能です。

ご感想・ご要望など、コメントをしていただけると励みになります! ここまでお読みくださりありがとうございました!

GitHub Gistにも同じコードを掲載しておりますので、お好きな方をご使用下さい。

おすすめの記事