TextSpan's text doesn't show if it overflows

Viewed 99

That's how it looks when I have a WidgetSpan and a TextSpan, and the text inside the TextSpan is too long:

problem

problem

A similar question has already been asked here TextSpan's text doesn't show if it overflows and is placed after WidgetSpan, but the one answer isn't suitable for my problem.

I have two Text.rich() widgets (which each host one WidgetSpan and one TextSpan) inside an Expanded widget, both Expanded with flex:1, because I want them to be the same size and take as much space as they can. That's why a row is not an option, you can't (as far as I know) put two rows side by side, at this happens...

using rows

using rows

This is how it's supposed to look like, just with the TextOverflow.ellipsis, if the text is too long:

target UI

target ui

Here is my code:

                Row(
                  children: [
                    Expanded(
                      flex: 1,
                      child: Text.rich(
                        TextSpan(children: [
                          WidgetSpan(
                            child: Container(
                              margin: const EdgeInsets.only(right: 4.0),
                              child: SvgPicture.asset("assets/icons/building.svg", color: 
                                     htLightGrey),
                            ),
                          ),
                          TextSpan(
                            text: incident.building.name,
                            style: const TextStyle(
                              fontWeight: FontWeight.normal,
                              fontSize: 16.0,
                              color: htLightGrey, /*overflow: TextOverflow.ellipsis*/
                            ),
                          ),
                        ]),
                        maxLines: 1,
                        overflow: TextOverflow.ellipsis,
                      ),
                    ),
                    Expanded(
                      flex: 1,
                      child: incident.department != null
                          ? Text.rich(
                              TextSpan(children: [
                                WidgetSpan(
                                  child: Container(
                                    margin: const EdgeInsets.only(right: 4.0),
                                    child: SvgPicture.asset("assets/icons/department.svg", 
                                           color: htLightGrey),
                                  ),
                                ),
                                TextSpan(
                                  text: incident.department!.name,
                                  style: const TextStyle(fontWeight: FontWeight.normal, 
                                         fontSize: 16.0, color: htLightGrey, overflow: 
                                         TextOverflow.ellipsis),
                                ),
                              ]),
                              maxLines: 1,
                              overflow: TextOverflow.ellipsis,
                            )
                          : const SizedBox.shrink(),
                    )
                  ],
                )
2 Answers

While we like to archive this UI, we are using Row as parent widget, which is perfect. Then we can split the row into tree part, left two part will get same and maximum available width. For this scenario, widget structure as follows.

Row(
  mainAxisSize: MainAxisSize.min,
  children: [
    Expanded(
      flex: 1,
      child: Container(
        color: Colors.green,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start, //start from left
          children: [
            buildItem(
                text:
                    "incident.buildi cident.buildi cident.buildi cident.buildi cident.building.name"),
            buildItem(text: "incide ing.ssss"),
          ],
        ),
      ),
    ),
    Expanded(
      flex: 1,
      child: Container(
        color: Colors.red,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            buildItem(text: "i ent.building.name"),
            buildItem(text: "incident.building.ssss"),
          ],
        ),
      ),
    ),
    IconButton(
      onPressed: () {},
      iconSize: 33,
      icon: Icon(Icons.arrow_right),
    ),
  ],
),

And inside Text.rich add use alignment: PlaceholderAlignment.middle, on WidgetSpan to set the middle.

maxLines: 1,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.start,

And you will get

enter image description here

I am using extra container to point the UI, simply remove the container from the column. Also, you can use Row instead of Rich Text.

Test widget

class _TestGroundState extends State<TestGround> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Column(
      children: [
        Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            Expanded(
              flex: 1,
              child: Container(
                color: Colors.green,
                child: Column(
                  crossAxisAlignment:
                      CrossAxisAlignment.start, //start from left
                  children: [
                    buildItem(
                        text:
                            "incident.buildi cident.buildi cident.buildi cident.buildi cident.building.name"),
                    buildItem(text: "incide ing.ssss"),
                  ],
                ),
              ),
            ),
            Expanded(
              flex: 1,
              child: Container(
                color: Colors.red,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    buildItem(text: "i ent.building.name"),
                    buildItem(text: "incident.building.ssss"),
                  ],
                ),
              ),
            ),
            IconButton(
              onPressed: () {},
              iconSize: 33,
              icon: Icon(Icons.arrow_right),
            ),
          ],
        ),
      ],
    ));
  }

  Text buildItem({
    required String text,
  }) {
    return Text.rich(
      TextSpan(
        children: [
          WidgetSpan(
            alignment: PlaceholderAlignment.middle,
            child: Container(
              child: Icon(Icons.ac_unit),
            ),
          ),
          TextSpan(
            text: text,
            style: TextStyle(
              fontWeight: FontWeight.normal,
              fontSize: 16.0,
            ),
          ),
        ],
      ),
      maxLines: 1,
      overflow: TextOverflow.ellipsis,
      textAlign: TextAlign.start,
    );
  }
}

More about flutter layout

To achieve your target Ui, use the Wrap widget instead of the Row widget. Here, when the contents of the widget overflow/exceed it will break it to the next line, hence you'll achieve your target Ui.

Related