I’m just trying to use ExpansionTile in Flutter, from example I modified to become like this:

I want to hide the arrow and use Switch to expand the tile, is it possible? Or do I need custom widget which render children programmatically? Basically, I just need to show/hide the children
Here’s my code:
import 'package:flutter/material.dart';
void main() {
runApp(ExpansionTileSample());
}
class ExpansionTileSample extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('ExpansionTile'),
),
body: ListView.builder(
itemBuilder: (BuildContext context, int index) =>
EntryItem(data[index]),
itemCount: data.length,
),
),
);
}
}
// One entry in the multilevel list displayed by this app.
class Entry {
Entry(this.title,[this.question='',this.children = const <Entry>[]]);
final String title;
final String question;
final List<Entry> children;
}
// The entire multilevel list displayed by this app.
final List<Entry> data = <Entry>[
Entry(
'Chapter A',
'',
<Entry>[
Entry(
'Section A0',
'',
<Entry>[
Entry('Item A0.1'),
Entry('Item A0.2'),
Entry('Item A0.3'),
],
),
Entry('Section A1','text'),
Entry('Section A2'),
],
),
Entry(
'Chapter B',
'',
<Entry>[
Entry('Section B0'),
Entry('Section B1'),
],
),
Entry(
'Chapter C',
'',
<Entry>[
Entry('Section C0'),
Entry('Section C1')
],
),
];
// Displays one Entry. If the entry has children then it's displayed
// with an ExpansionTile.
class EntryItem extends StatelessWidget {
const EntryItem(this.entry);
final Entry entry;
Widget _buildTiles(Entry root) {
if (root.children.isEmpty) return Container(
child:Padding(
padding: const EdgeInsets.symmetric(
vertical: 8.0,
horizontal: 32.0,
),
child:Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children:[
Text(root.title),
Divider(height: 10.0,),
root.question=='text'?Container(
width: 100.0,
child:TextField(
decoration: const InputDecoration(helperText: "question")
),
):Divider()
]
)
)
);
return ExpansionTile(
//key: PageStorageKey<Entry>(root),
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children:[
Text(root.title),
Switch(
value:false,
onChanged: (_){},
)
]
),
children: root.children.map(_buildTiles).toList(),
);
}
@override
Widget build(BuildContext context) {
return _buildTiles(entry);
}
}
@diegoveloper 's answer is almost ok,one small issue not covereed is: it doesn't propogate click on Switch further to ExpansionTile, so if you click outside switch it's expanding, while clicking on Switch does nothing. Wrap it with IgnorePointer, and on expansion events set the value for switch. It's a bit backwards logic, but works good.
...
return ExpansionTile(
onExpansionChanged: _onExpansionChanged,
// IgnorePointeer propogates touch down to tile
trailing: IgnorePointer(
child: Switch(
value: isExpanded,
onChanged: (_) {},
),
),
title: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Text(root.title),
]),
children: root.children.map((entry) => EntryItem(entry)).toList(),
);
...
I think this will help you initiallyExpanded : true
itemBuilder: (context, index) {
return Column(
children: <Widget>[
Divider(
height: 17.0,
color: Colors.white,
),
ExpansionTile(
key: Key(index.toString()), //attention
initiallyExpanded : index==selected, //attention
leading: Icon(Icons.person, size: 50.0, color: Colors.black,),
title: Text('Faruk AYDIN ${index}',style: TextStyle(color: Color(0xFF09216B), fontSize: 17.0, fontWeight: FontWeight.bold)),
subtitle: Text('Software Engineer', style: TextStyle(color: Colors.black, fontSize: 13.0, fontWeight: FontWeight.bold),),
children: <Widget>[
Padding(padding: EdgeInsets.all(25.0),
child : Text('DETAİL ${index} \n' + 'It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using "Content here, content here", making it look like readable English.',)
)
],
onExpansionChanged: ((newState){
if(newState)
setState(() {
Duration(seconds: 20000);
selected = index;
});
else setState(() {
selected = -1;
});
})
),
]
);
Yes, it's possible, I modified your code a little :
class EntryItem extends StatefulWidget {
const EntryItem(this.entry);
final Entry entry;
@override
EntryItemState createState() {
return new EntryItemState();
}
}
class EntryItemState extends State<EntryItem> {
var isExpanded = false;
_onExpansionChanged(bool val) {
setState(() {
isExpanded = val;
});
}
Widget _buildTiles(Entry root) {
if (root.children.isEmpty)
return Container(
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 8.0,
horizontal: 32.0,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(root.title),
Divider(
height: 10.0,
),
root.question == 'text'
? Container(
width: 100.0,
child: TextField(
decoration: const InputDecoration(
helperText: "question")),
)
: Divider()
])));
return ExpansionTile(
onExpansionChanged: _onExpansionChanged,
trailing: Switch(
value: isExpanded,
onChanged: (_) {},
),
//key: PageStorageKey<Entry>(root),
title: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Text(root.title),
]),
children: root.children.map((entry) => EntryItem(entry)).toList(),
);
}
@override
Widget build(BuildContext context) {
return _buildTiles(widget.entry);
}
}
Basically I changed from Stateless to Stateful because you need to handle the state of your Switch widget.
There is a trailing property from ExpansionTile where I put the Switch to remove the arrow widget by default.
Listen the onExpansionChanged: _onExpansionChanged,, to change the status of the Switch.
And finally build the children as new widgets:
children: root.children.map((entry) => EntryItem(entry)).toList(),
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With