Flutter:How to remove elevation from ExpansionPanelList?

Viewed 6664

I was trying to list dropdown like widget, but luckily found the expansion panel list widget to get my desired UX to feel.

So, I am using ExpansionPanelList in my flutter app, but don't require the default elevation/border-shadow it comes with.

I have no idea how to remove it, so as to make it look part of the body rather than an elevated container.

Currently looking like this:

mock

Following is my code:

class _PracticetestComp extends State<Practicetest> {
  var listofpracticetest;
  List<Item> _data = [
    Item(
      headerValue: 'Previous Question Papers',
      expandedValue: '',
    )
  ];


  @override
  Widget build(BuildContext context) {
    return Scaffold(
        backgroundColor: Color(0xffF8FDF7),
        appBar: AppBar(
          backgroundColor: Color(0xffF8FDF7), // status bar color
          brightness: Brightness.light,
          elevation: 0.0,
          leading: Container(
            margin: EdgeInsets.only(left: 17),
            child: RawMaterialButton(
              onPressed: () {
                Navigator.pushNamed(context, '/');
              },
              child: new Icon(
                Icons.keyboard_backspace,
                color: Colors.red[900],
                size: 25.0,
              ),
              shape: new CircleBorder(),
              elevation: 4.0,
              fillColor: Colors.white,
              padding: const EdgeInsets.all(5.0),
            ),
          ),
        ),
        body: Container(
          // height: 200,
          margin: EdgeInsets.only(top: 40),
          child: ListView(
            shrinkWrap: true,
            scrollDirection: Axis.vertical,
            children: [
              Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[

                  Container(
                      margin: EdgeInsets.only(top: 30),
                      child: Theme(
                          data: Theme.of(context)
                              .copyWith(cardColor: Color(0xffF8FDF7)),
                          child: _buildPanelPreviousPapers()))
                ],
              )
            ],
          ),
        ));
  }

  Widget _buildPanelPreviousPapers() {
    return ExpansionPanelList(
      expansionCallback: (int index, bool isExpanded) {
        setState(() {
          _data[index].isExpanded = !isExpanded;
        });
      },
      children: _data.map<ExpansionPanel>((Item item) {
        return ExpansionPanel(
          headerBuilder: (BuildContext context, bool isExpanded) {
            return ListTile(
              title: Text(item.headerValue),
            );
          },
          body: Container(

            child: ListTile(
              leading: Text(
                'Alegbra',
                style:
                    TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
              ),

              ),
            ),
          ),
          isExpanded: item.isExpanded,
        );
      }).toList(),
    );
  }
}

// stores ExpansionPanel state information
class Item {
  Item({
    this.expandedValue,
    this.headerValue,
    this.isExpanded = false,
  });

  String expandedValue;
  String headerValue;
  bool isExpanded;
}
6 Answers

wrap your entire expansion widget child inside Material widget and change the elevation based on expansion child is expanded or not with method

   Material(
        elevation: isSelected ? 4 : 0,
        child: ExpansionTile(
         onExpansionChanged:(value){
                            isSelected=value;
                            setState(){};
                                   },

         title: getExpantionTitle(context),
          children: getChildrentList(),
              ),
            ),
        ),

in case if you don't like divider in ExpansionTile tile do some thing like this

        final theme = Theme.of(context).copyWith(dividerColor: 
        Colors.transparent);
     //use as a child 
 child:Theme(data: theme, child: ExpansionTile(...));  

First, it isn't recommended to not use elevation for ExpansionPanelList according to Material design spec.

However, if you really want to do that, there are 2 solutions for you, either you create your own custom ExpansionPanelList, or get ready to add couple of lines to the source file. I'm providing you the latter solution.

  1. Open expansion_panel.dart file, go to the build() method of _ExpansionPanelListState and make following changes

    return MergeableMaterial(
      hasDividers: true,
      children: items,
      elevation: 0, // 1st add this line
    );
    
  2. Now open mergeable_material.dart file, navigate to _paintShadows method of _RenderMergeableMaterialListBody class and make following changes:

    void _paintShadows(Canvas canvas, Rect rect) {
    
      // 2nd add this line
      if (boxShadows == null) return;
    
      for (final BoxShadow boxShadow in boxShadows) {
        final Paint paint = boxShadow.toPaint();
        canvas.drawRRect(kMaterialEdges[MaterialType.card].toRRect(rect), paint);
      }
    }
    

Screenshot:

enter image description here

Just add this line:

ExpansionPanelList(
      elevation: 0, // this line
      expansionCallback: ...

I would wrap it in a ClipRect.

  Widget _buildPanelPreviousPapers() {
    final panel = ExpansionPanelList(
      expansionCallback: (int index, bool isExpanded) {
        setState(() {
          _data[index].isExpanded = !isExpanded;
        });
      },
      children: _data.map<ExpansionPanel>((Item item) {
        return ExpansionPanel(
          headerBuilder: (BuildContext context, bool isExpanded) {
            return ListTile(
              title: Text(item.headerValue),
            );
          },
          body: Container(
            child: ListTile(
              leading: Text(
                'Alegbra',
                style:
                    TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
              ),

              ),
            ),
          ),
          isExpanded: item.isExpanded,
        );
      }).toList(),
    );
    return ClipRect(child: panel);
  }

To alter the default card background color add a Theme override:

    return ClipRect(
      child: Theme(
        data: Theme.of(context).copyWith(cardColor: Colors.pink),
        child: child,
      ),
    );
Related