Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to get rid of the spacing between expansion panels when expanded in an expansion panel list in Flutter?

I am running into a problem where I am wanting to remove the space between expansion panels of an expansion panel list when the panels are expanded.

Images of unwanted behavior, these images are taken from flutter documentation:

List when not expanded, which is fine:

enter image description here

List when expanded: - You can see the gap between the sections. This is what I do not want for my app.

enter image description here

Any tips are appreciated.

like image 662
varmkun Avatar asked Mar 05 '20 22:03

varmkun


2 Answers

Try Modifying The Actual Implementations

If you have some prior programming experience, this should make sense...

Find these files:

  • expansion_panel.dart
  • expansion_title.dart
  • expand_icon.dart
  • mergeable_material.dart

These files should be located in the External Library > Dart Packages > Flutter > src > material. Note that the material folder may be expressed as "src.material".

Android Studio should allow you to hover over the ExpansionPanel Widget and right-click it. After right-clicking it you should see a list of shortcuts, one being "Go to". Click on the "Go to" option which should bring up more options, one of which being "Implementation(s)". This should bring you to where you need. According to my version, double clicking the widget name so the entire widget's name is highlighted should allow for a keyboard shortcut Ctrl+Alt+B.

The key file you must go into is "mergeable_material.dart". In "mergeable.dart", go to the MaterialGap constructor:

const MaterialGap({
    @required LocalKey key,
    this.size = 16.0, 
    //This is the size of the gap between ExpansionTiles WHEN EXPANDED
}) : assert(key != null),
   super(key);

This size variable controls the gap between the Expansion Tiles ONLY when EXPANDED. Setting "this.size = 0.0" should remove the gap.

If you want to know why this is, long story short, when the ExpansionPanels list of widgets property is being defined (which is in expansion_panel.dart) a "MaterialGap" is being added between the children. We modified the material gap to be 0.0 thus effectively removing the gap.

Other things you can do:

  1. Change the Trailing Icon in the Header.

    Go to expand.dart file. Go to the bottom of the file where the build method should be. In the return statement, replace the icon button with 'whatever' you want (within reason).

    @override
    Widget build(BuildContext context) {
      assert(debugCheckHasMaterial(context));
      assert(debugCheckHasMaterialLocalizations(context));
      final MaterialLocalizations localizations = MaterialLocalizations.of(context);
      final String onTapHint = widget.isExpanded ? localizations.expandedIconTapHint : 
      localizations.collapsedIconTapHint;
    
      return Semantics(
        onTapHint: widget.onPressed == null ? null : onTapHint,
        child: Container() //Replaced the Icon Button here to remove it
      );
    }
    

    Keep in mind that without a button, you must make canTapOnHeader: true, or you won't be able to expand the panel. You can make sure you don't forget to do this by going to the ExpansionPanel constructor and changing "this.canTapOnHeader = false;" to "this.canTapOnHeader = true;

      ExpansionPanel({
        @required this.headerBuilder,
        @required this.body,
        this.isExpanded = false,
        this.canTapOnHeader = true, //Changed this to true from false
      }) : assert(headerBuilder != null),
           assert(body != null),
           assert(isExpanded != null),
           assert(canTapOnHeader != null);
    
  2. Remove the shadow and/or dividers

    Go to the bottom of the expansion_panel.dart file. This is where the build method should be. At the bottom of the build method should be the return statement, which returns MergeableMaterial. You can do the following:

      return MergeableMaterial(
        hasDividers: false, //Change the boolean value of this
        children: items,
        elevation: 0, 
        //Add this line to remove shadow from elevation, REQUIRES ANOTHER STEP             
      );
    

    If add the "elevation: 0" property you MUST go back to mergeable_material.dart and add the following line of code:

    void _paintShadows(Canvas canvas, Rect rect) {
        if (boxShadows == null) return; //ADD THIS LINE OF CODE
        for (BoxShadow boxShadow in boxShadows) {
          final Paint paint = boxShadow.toPaint();
          // TODO(dragostis): Right now, we are only interpolating the border radii
          // of the visible Material slices, not the shadows; they are not getting
          // interpolated and always have the same rounded radii. Once shadow
          // performance is better, shadows should be redrawn every single time the
          // slices' radii get interpolated and use those radii not the defaults.
          canvas.drawRRect(kMaterialEdges[MaterialType.card].toRRect(rect), paint);
        }
    }
    

I think you get the idea, You can do more to remove padding and whatnot by messing around with constants.

Concerns

Note: I'm relatively new to flutter, (2 months last summer and 2 months now- I'm a college student) in fact. I don't know how modifying these files may impact other widgets but I haven't noticed any issues by doing this. This is also my first post so take it with a grain of salt. Modifying Material implementations may break some rules or conventions that I would refer to the documentation for.

like image 131
Alex Badia Avatar answered Nov 15 '22 19:11

Alex Badia


Instead of changing the source code, you're better off making a copy of the expansion_panel.dart and using this. For the space between the items to disappear, you must comment out on lines 486 and 487.

if (_isChildExpanded(index) && index != 0 && !_isChildExpanded(index - 1))
items.add(MaterialGap(key: _SaltedKey<BuildContext, int>(context, index * 2 - 1)));

And on lines 558 and 559.

if (_isChildExpanded(index) && index != widget.children.length - 1)
items.add(MaterialGap(key: _SaltedKey<BuildContext, int>(context, index * 2 + 1)));

Another issue with this component which you might want to fix, is with the canTapOnHeader property. Setting it to true allows you to tap the card and expand, but you're stuck with a bunch of dead space on the right side of your card. To fix this, add a check to only show expandIconContainer (line 526) as follows:

if (!child.canTapOnHeader) expandIconContainer,
like image 4
Tim Jacobs Avatar answered Nov 15 '22 18:11

Tim Jacobs