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:
[2
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