【Flutter小技集】TextSpanでforループ回して、間に「・」打ちたい時

## 今日の主役
Flutterで同じ行に様々なフォントやスタイルを混在させるのに便利な**`RichText`**クラス

こいつ(RichText)に表示させる複数の文言をDBから配列で取得して、ループ処理でWidgetを生成して渡そうと思ってたんだけども、ちょっとつまづいたので備忘録含めて小技紹介です。

## やりたかった事
簡単に言うと、
- 表示したい文言が格納されてる配列を取得
- それをループ処理で`RichText`に渡し、描画させる

こんなイメージです⬇︎
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/334813/f778ecab-6089-b2a9-57ca-6ed6d7a52593.png" border="2">
それぞれの決済方法に下線を引き、その間に区切りの「・」を入れる。プラス現金払いをその他の決済方法と区別する為に「と現金払い」という風に「と」を頭に付けたい感じでした。
## 試した事
「・」や「と」をどのタイミングで打てば良いかはその文字列が何番目か知る必要があります。なので配列の値だけでなく、indexもくれる`List<T>.generate()`を使おう。(他にも色々書き方はあるので、それはまたどこかで触れたいと思います。)

それをいざchildrenのListに渡した結果、「`List<TextSpan>`なんて渡してくるんじゃないよ！`TextSpan`しか私は受けとんないよ！」と怒られてしまう。

ううう、でもindex使いたいから`List.generate()`がいいんですもの...


```dart:うまくいかない
final List<String> list = <String>['クレジットカード','交通系ICカード','現金払い'];

@override 
Widget build(BuildContext context){
   return Container(
      child: RichText(
        text: TextSpan(
         children: <TextSpan>[ // <TextSpan>しか受け取らないよ！
            List<InlineSpan>.generate(  // List<TextSpan>なんて渡してくるんじゃないよ！
                list.length,
                (int index){
                  return TextSpan(
                      children: <TextSpan> [
                        if(index != 0 && list[index] != '現金払い')
                          const TextSpan(text:'・'),
                        if(index != 0 && list[index] == '現金払い')
                          const TextSpan(text:'と'),
                        TextSpan(
                          text: list[index],
                          style: const TextStyle(
                            decoration: TextDecoration.underline,
                          ),
                        ),
                      ],
                  );
                },
              ),
            ],
         ),
       ),
    );
  }
```

## 結論：childrenプロパティに直で渡せ！
結論としてはchildrenに渡した`List<TextSpan>`の中で記述するのではなく、単純にchildrenに直で渡せば良かった。

ちなみに`InlineSpan`というのは`TextSpan`の親クラスになります。

```dart:うまくいく
final List<String> list = <String>['クレジットカード','交通系ICカード','現金払い'];

@override 
Widget build(BuildContext context){
   return Container(
      child: RichText(
        text: TextSpan(
         children: List<InlineSpan>.generate( // ⬅︎ ココ！直渡し
            list.length,
            (int index){
               return TextSpan(
                  children: <TextSpan> [
                    if(index != 0 && list[index] != '現金払い')
                      const TextSpan(text:'・'),
                    if(index != 0 && list[index] == '現金払い')
                      const TextSpan(text:'と'),
                    TextSpan(
                      text: list[index],
                      style: const TextStyle(
                        decoration: TextDecoration.underline,
                      ),
                    ),
                  ],
               );
             },
          ),
        ),
       ),
    );
  }

```

## そしてもっとスマートな書き方
こちらの記事の誤りについてご指摘してくださった@kabochapoさんがよりスマートな書き方を教えてくださいました。ありがとうございます！

`list.first`で配列の頭の値かを判別する事ができるのでそもそもindex無くても今回の要件は満たせる様です。それを使えば`List.generate()`で記述する必要がなくなるので、children配下のList内でfor文を回し、やりたかった事を達成できました！

```dart:スマート
  final List<String> list = <String>['クレジットカード', '交通系ICカード', '現金払い'];

  @override
  Widget build(BuildContext context) {
    return Container(
      child: RichText(
        text: TextSpan(
          children: <TextSpan>[
            for (String type in list) ...<TextSpan>[
              if (type != list.first && type != '現金払い')
                const TextSpan(text: '・'),
              if (type == list.first && type == '現金払い')
                const TextSpan(text: 'と'),
              TextSpan(
                text: type,
                style: const TextStyle(
                  decoration: TextDecoration.underline,
                ),
              ),
            ],
          ],
        ),
      ),
    );
  }
```
ベリースマート

## 参考
https://stackoverflow.com/questions/56947046/flutter-for-loop-to-generate-list-of-widgets
https://stackoverflow.com/questions/61922116/flutter-how-to-use-to-have-different-kind-of-widgets-in-for-loops