Search code examples
flutteranimationtrailingexpansion-tile

(Inside ListView.builder) Every time I press the ExpansionTile, the trailing icon of the ExpansionTile changes also on other ExpansionTiles


I have ListView.builder which returns ExpansionTile. Inside of this ExpansionTile, I used trailing with row widget. When I use row inside of the trailing, I lost the animation effect, therefore I used AnimatedRotation widget. But now every other ExpansionTile's trailing icon changes its direction.

Is there any way to prevent this behaviour? I just want the animate the trailing icon of the ExpansionTile that I pressed to change.

Note: I aim to put trailing with text and icon with proper turn animation. If there are any other solutions rather than using trailing with row I am open to recommendations.

Here is my code

ListView.builder(
        itemCount: 15,
        itemBuilder: (context, index) {
          return ExpansionTile(
            iconColor: Colors.red,
            textColor: Colors.grey.shade900,
            childrenPadding: EdgeInsets.symmetric(horizontal: 0, vertical: 0),
            expandedCrossAxisAlignment: CrossAxisAlignment.stretch,
            tilePadding: EdgeInsets.symmetric(
              vertical: 0,
              horizontal: 10,
            ),
            leading: Icon(Icons.ac_unit),
            trailing: Row(
              mainAxisSize: MainAxisSize.min,
              children: [
                Text("60.00₺"),
                AnimatedRotation(
                    turns: _isExpanded ? .5 : 0,
                    duration: Duration(milliseconds: 200),
                    child: Icon(Icons.expand_more)),
              ],
            ),
            onExpansionChanged: (value) {
              setState(() {
                _isExpanded = value;
              });
            },
            title: Text(
              "22.04.2022",
              style: TextStyle(
                  fontSize: 20,
                  color: Color(AppColors.blacktextcolor),
                  fontWeight: FontWeight.bold),
            ),
            subtitle: Text("Bekliyor"),
            children: <Widget>[
              ListTile(
                title: Text(
                  "Talep Eden",
                  style: TextStyle(color: Colors.grey, fontSize: 13),
                ),
                subtitle: Text(
                  "Sertan Yıldız",
                  style: TextStyle(color: Colors.blue, fontSize: 18),
                ),
              ),
             
            ],
          );
        },
      ),

https://gifyu.com/image/S3J5c


Solution

  • you need to store the state of the expanded widgets in a list.

    Generate a list with a false or true state for all expansion tiles and then use that state based on the index for each tile.

    Take a look at the following code below:

    class MyWidget extends StatefulWidget {
      const MyWidget({Key? key}) : super(key: key);
    
      @override
      State<MyWidget> createState() => _MyWidgetState();
    }
    
    class _MyWidgetState extends State<MyWidget> {
      
     List<bool> _isExpandedStateList =
        List<bool>.generate(15, (int index) => false);
      
      @override
      Widget build(BuildContext context) {
        return ListView.builder(
            itemCount: 15,
            itemBuilder: (context, index) {
              bool _isExpanded = _isExpandedStateList[index];
              return ExpansionTile(
                iconColor: Colors.red,
                textColor: Colors.grey.shade900,
                childrenPadding: EdgeInsets.symmetric(horizontal: 0, vertical: 0),
                expandedCrossAxisAlignment: CrossAxisAlignment.stretch,
                tilePadding: EdgeInsets.symmetric(
                  vertical: 0,
                  horizontal: 10,
                ),
                leading: Icon(Icons.ac_unit),
                trailing: Row(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Text("60.00₺"),
                    AnimatedRotation(
                        turns: _isExpanded ? .5 : 0,
                        duration: Duration(milliseconds: 200),
                        child: Icon(Icons.expand_more)),
                  ],
                ),
                onExpansionChanged: (value) {
                  setState(() {
                    _isExpandedStateList[index] = value;
                  });
                },
                title: Text(
                  "22.04.2022",
                  style: TextStyle(
                      fontSize: 20,
                      color: Colors.blue,
                      fontWeight: FontWeight.bold),
                ),
                subtitle: Text("Bekliyor"),
                children: <Widget>[
                  ListTile(
                    title: Text(
                      "Talep Eden",
                      style: TextStyle(color: Colors.grey, fontSize: 13),
                    ),
                    subtitle: Text(
                      "Sertan Yıldız",
                      style: TextStyle(color: Colors.blue, fontSize: 18),
                    ),
                  ),
                 
                ],
              );
            },
          );
      }
    }
    
    

    Let me know if you have any doubts.