Home > Mobile >  How to measure widget width and check for fit in container
How to measure widget width and check for fit in container

Time:08-22

I have a list of items that I want to display in non-scrollable horizontal layout.

In the example below, I have 5 items, 2 of them are fully displayed and the other 3 do not fit, hence the ' 3' label.

enter image description here

I do not mind if there is some empty space after the label, but the important thing is that we only display items that fully fit in the row.

I guess the main problem is how can I test that a widget fits based on it's width into a row?

I thought about VisibilityDetector, but I will ended up rendering all widgets, then removing the ones that are not 100% visible, and the entire logic seems quite flawed for this use case.

Any ideas? Thanks

CodePudding user response:


EDIT: Included dynamic width based in label length

Try this, with defined width of item container and the label or with dynamic calculating the width based on font size.

Change useFixedWidth to true or false if you want dynamic or static width.

Example in a Stateless widget:

class MyWidget extends StatelessWidget {
  final double itemWidth = 100; //maxwidth if item container
  final double labelWidth = 40; //maxWidth of  label

  List<String> items = List.generate(
      10, (index) => 'Name ${index   1}'); //replace with a real list of items
  final bool useFixedWidth =
      false; // define if want to calculate dynamic with of each item
  final double letterWidth =
      12; // defined width of a letter || change depending on font size

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(builder: (context, constraints) {
      int totalItems = items.length;
      int maxDisplayItems = 0;
      List<double> dynamicItemsWidth = []; //if want to use dynamic width

      if (useFixedWidth) {
        //if want to use fixed width
        maxDisplayItems =
            (((constraints.maxWidth - labelWidth) / itemWidth).floor()).clamp(
                0, totalItems); //check how many items fit including the  label

      } else {
        //if want to calculate based on string length
        dynamicItemsWidth = items
            .map((e) => e.length * letterWidth)
            .toList(); //calculate individual item width

        double _acumWidth = 0.0;
        for (var width in dynamicItemsWidth) {
          _acumWidth = _acumWidth   width;
          if (_acumWidth < (constraints.maxWidth - labelWidth)) {
            maxDisplayItems  ;
          }
        }
      }

      bool showPlusSign =
          maxDisplayItems < totalItems; //check if all items can be shown
      return Row(children: [
        Row(
            children: List.generate(maxDisplayItems, (index) {
          return SizedBox(
              height: itemWidth,
              width: useFixedWidth ? itemWidth : dynamicItemsWidth[index],
              child: Container(
                  //color: Colors.red,
                  //width: itemWidth,
                  child: Center(child: Text('Name ${index   1}'))));
        }).toList()),
        if (showPlusSign)
          SizedBox(
              width: labelWidth,
              height: itemWidth,
              child: Center(child: Text(' ${totalItems - maxDisplayItems}')))
      ]);
    });
  }
}

shows this dynamic layout for 10 items:

enter image description here

CodePudding user response:

https://pub.dev/packages/auto_size_text

Please use this package and it will resize the text based on the available space

AutoSizeText(
  'Name1, Name2,  3',
  style: TextStyle(fontSize: 20),
  maxLines: 1,
)
  • Related