Home > Enterprise >  Expansion tile trailing icon updates all in list on interaction with one tile. How can I only change
Expansion tile trailing icon updates all in list on interaction with one tile. How can I only change

Time:12-20

How do I make it so that the icon will only update for the tile that was clicked? Right now, the behavior is that all icons update when clicking on one tile.

Here is the code (trimmed to only include relevant parts):

Column(children: List.generate(
    filteredFAQ.length,
    (index) => Column(
        children: [
            if(index > 0) {
                Container(
                    child: Column(
                        children: <Widget>[
                            ExpansionTile(
                            trailing: SvgPicture.string(
                                isQuestionClicked
                                    ? addPayeeArrowUp
                                    : rightArrow,
                                color: primary,
                              ),
                              onExpansionChanged:
                                  (bool expanded) {
                                setState(() {
                                  isQuestionClicked = expanded;
                                });
                              },
                            ),
                        ],
                    )
                )
            }
        ]
    )
),);

here are screenshots of the behavior:

beforeClickingOneTile

[afterClickingOneTile2

I used the in built onExpansionChange of the ExpansionTile.

CodePudding user response:

To only change the icon of the expanded tile, you can use this approach:

create a Map:

Map<int, bool> state = {};

and use it accordingly in your ExpansionTile to check whether it's selected, if the value is true or false:

 List.generate(6, (index) {
          return ExpansionTile(
            title: Text('Item $index'),
            trailing: state[index] ?? false
                ? Icon(Icons.arrow_drop_up)
                : Icon(Icons.arrow_drop_down),
            onExpansionChanged: (value) {
              setState(() {
                state[index] = value;
              });
            },
            children: [
              Container(
                height: 100,
                color: Colors.red,
              ),
            ],
          );
        }),

Complete runnable example:

import 'package:flutter/material.dart';

const Color darkBlue = Color.fromARGB(255, 18, 32, 47);

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark().copyWith(
        scaffoldBackgroundColor: darkBlue,
      ),
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: MyWidget(),
        ),
      ),
    );
  }
}

class MyWidget extends StatefulWidget {
  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  Map<int, bool> state = {};

  bool isExpanded = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Demo Home Page'),
      ),
      body: Column(
        children:
            // generate 6 ExpansionTiles
            List.generate(6, (index) {
          return ExpansionTile(
            title: Text('Item $index'),
            trailing: state[index] ?? false
                ? Icon(Icons.arrow_drop_up)
                : Icon(Icons.arrow_drop_down),
            onExpansionChanged: (value) {
              setState(() {
                state[index] = value;
              });
            },
            children: [
              Container(
                height: 100,
                color: Colors.red,
              ),
            ],
          );
        }),
      ),
    );
  }
}

CodePudding user response:

You have to manage each childrens state separatory. I think it's best to manage them in filteredFAQ by adding

bool isExpanded

property there. but you can achive by manage them as separated property like

final items = List<bool>.generate(filteredFAQ.length, (index) => false);

and change their state when they're expanded

items[index] = !items[index]

here's a sample complete code

Column(children: List.generate(
    filteredFAQ.length,
    (index) => Column(
        children: [
            if(index > 0) {
                Container(
                    child: Column(
                        children: <Widget>[
                            ExpansionTile(
                            trailing: SvgPicture.string(
                                items[index]
                                    ? addPayeeArrowUp
                                    : rightArrow,
                                color: primary,
                              ),
                              onExpansionChanged:
                                  (bool expanded) {
                                setState(() {
                                  items[index] = !items[index];
                                });
                              },
                            ),
                        ],
                    )
                )
            }
        ]
    )
),);

And don't forget to initalize items at where you initialize filteredFAQ

If you provide a whole code in the widget I can complete it if you need more information

  • Related