dropdown_button2 icon indicating copy to clipboard operation
dropdown_button2 copied to clipboard

How can i create menu items with exactly height for each element

Open brunos0 opened this issue 1 year ago • 0 comments

Hello.

I'm try to use Dropdown Button 2, but I having an issue about items heights. I have a list of strings with different length like:

ITEM 1 ITEM 2 AND ANOTHER DETAIL ITEM 3 AND ANOTHER SO LONG DETAIL ITEM 4 DETAIL ITEM 5 D3T41L ITEM 6 ITEM 7 AND ANOTHER AMAZING SO LOOOOONGGGGG DETAIL DESCRIPTION

I`m trying to calculate the height for each item, but even much similar description the height gets different and the result looks like:

ITEM 1 -------

ITEM 2 AND ANOTHER DETAIL ------- ITEM 3 AND ANOTHER SO LONG DETAIL ------- ITEM 4 DETAIL ------- ITEM 5 D3T41L

-------

.....

It's very difficult calculate the precise height for each element.

I'm create DropdownMenuItem like this:

List<DropdownMenuItem<String>> _addDividersAfterItems(
   List<UniqueKey> keys,
   bool isSmallScreen,
 ) {
   final menuItems = <DropdownMenuItem<String>>[];

   for (var index = 0; index < values.length; index++) {
     menuItems.addAll(
       [
         DropdownMenuItem<String>(
           key: keys[index],
           value: values[index]['id'],
           child: Text(
             values[index]['nome'] ?? '',
             style: const TextStyle(
               fontSize: 14,
             ),
             softWrap: true,
           ),
         ),
         //If it's last item, we will not add Divider after it.
         if (index != values.length - 1)
           const DropdownMenuItem<String>(
             enabled: false,
             child: Divider(),
           ),
       ],
     );
   }

   return menuItems;
 }

And calculate the height like this:

  List<double> _getCustomItemsHeights(
    double textScaleFactor,
    bool isSmallScreen,
  ) {
    final itemsHeights = <double>[];
    var itemIndex = 0;
    for (var i = 0; i < (values.length * 2) - 1; i++) {
      if (i.isEven) {
        final textSpan = TextSpan(
          text: values[itemIndex]['nome'],
          style: const TextStyle(fontSize: 14),
        );

        final textPainter = TextPainter(
          text: textSpan,
          textDirection: TextDirection.ltr,
          textScaleFactor: textScaleFactor,
          textWidthBasis: TextWidthBasis.longestLine,
        );

        double height;
        int lineCount;

        if (isSmallScreen) {
          textPainter.layout(maxWidth: 250);
          lineCount = textPainter.computeLineMetrics().length;

          height = textScaleFactor >= 1.3
              ? 14 * lineCount * textScaleFactor
              : 14 * lineCount * textScaleFactor;
        } else {
          textPainter.layout(maxWidth: maxLineWidth(textScaleFactor));
          lineCount = textPainter.computeLineMetrics().length;

          height = textScaleFactor >= 1.3
              ? 13 * lineCount * textScaleFactor
              : 25 * lineCount * textScaleFactor;
        }

        if (itemIndex == 0 && lineCount == 1) {
          height += 10;
        }
        itemsHeights.add(height);
        itemIndex++;
      }
      //Dividers indexes will be the odd indexes
      if (i.isOdd) {
        itemsHeights.add(10);
      }
    }
    return itemsHeights;
  }

Ps. maxLineWidth function is a custom method to give me the maxWidth for the current textScaleFactor.

But I think that I a solve this problem in scale 1.0, another scales works fine too.

Exist a better way to calculate the line height or just shirink the container for DropdownMenuItem shows only Text and divider?

Sorry about my English.

Kind Regards.

brunos0 avatar May 02 '24 17:05 brunos0