How to replace certain string/text in a list to Widget (GestureDetector) in Flutter

Viewed 84

I load a list of strings from json file. For example:
Joe waited for the <link>train</link>
The <link>car</link> was late
Mary and Samantha took the <link>bus</link>

In the listview.builder how to replace the text that is within <link></link> to be able to wrap in a GestureDetector widget?
From <link>train</link> to train (this train is clickable)
My code is as below:

ListView.builder(
   itemCount: book.sentence.length,
   itemBuilder: (context, index) {
      return Container(
         child: Row(
            children: [
               Flexible(
                  child: Text(book.sentence[index].content.toString())
                  )
               ],
          )
       );
    }
  ),

The current output result are:
Joe waited for the <link>train</link>
The <link>car</link> was late
Mary and Samantha took the <link>bus</link>

2 Answers

Let say we have list Like this:

List<String> _testList = [
    'Joe waited for the <link>train</link>',
    "The <link=\"64_abc\">car</link> was late, and John has to wait for <link='abc221'>bus</link>"
];

than try this:

ListView.builder(
          itemCount: _testList.length,
          itemBuilder: (context, index) {
            var text = _testList[index];

            List<InlineSpan> _children = [];
            if (text.contains('<link')) {
              var textList = text.split(' ');
              var textString = '';
              for (var element in textList) {
                if (element.contains('<link')) {
                  _children.add(
                    TextSpan(text: textString),
                  );

                  textString = ' ';

                  final startIndex = element.indexOf('>');

                  final endIndex = element.indexOf('</', startIndex);

                  var selectableText =
                      element.substring(startIndex + 1, endIndex);

                  _children.add(
                    WidgetSpan(
                      child: GestureDetector(
                        onTap: () {
                          print('$selectableText clicked');
                        },
                        child: Text(
                          selectableText,
                          style: TextStyle(fontWeight: FontWeight.bold),
                        ),
                      ),
                    ),
                  );
                } else {
                  textString = textString + element + ' ';
                }
              }

              if (textString != ' ') {
                  _children.add(
                    TextSpan(text: textString),
                  );
              }

              return Text.rich(
                TextSpan(
                  children: _children,
                ),
              );
            } else {
              return Text(text);
            }
          },
        )

enter image description here

Use RichText for each builder as follows, There you can add required style to indicate the text is clickable.

RichText(
      text: TextSpan(
        text: 'Joe waited for the ',
        style: DefaultTextStyle.of(context).style,
        children: <TextSpan>[
          TextSpan(
              text: 'train',
              style: const TextStyle(color: Colors.lightBlue),
              recognizer: TapGestureRecognizer()
                ..onTap = () => print('click')),
        ],
      ),
    ),
Related