我使用从how-to-create-expandable-listview-in-flutter获得的以下代码
要在Flutter中创建一个ExpandableListView
,并且我的应用程序需要显示一个项目,而在点击一个新项目时,它只能显示一个已展开的项目,而所有其他项目都可以折叠,请帮助我如何为此目的自定义代码
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(home: new Home()));
}
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Colors.grey,
appBar: new AppBar(
title: new Text("Expandable List"),
backgroundColor: Colors.redAccent,
),
body: new ListView.builder(
itemBuilder: (BuildContext context, int index) {
return new ExpandableListView(title: "Title $index");
},
itemCount: 5,
),
);
}
}
class ExpandableListView extends StatefulWidget {
final String title;
const ExpandableListView({Key key, this.title}) : super(key: key);
@override
_ExpandableListViewState createState() => new _ExpandableListViewState();
}
class _ExpandableListViewState extends State<ExpandableListView> {
bool expandFlag = false;
@override
Widget build(BuildContext context) {
return new Container(
margin: new EdgeInsets.symmetric(vertical: 1.0),
child: new Column(
children: <Widget>[
new Container(
color: Colors.blue,
padding: new EdgeInsets.symmetric(horizontal: 5.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new IconButton(
icon: new Container(
height: 50.0,
width: 50.0,
decoration: new BoxDecoration(
color: Colors.orange,
shape: BoxShape.circle,
),
child: new Center(
child: new Icon(
expandFlag ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down,
color: Colors.white,
size: 30.0,
),
),
),
onPressed: () {
setState(() {
expandFlag = !expandFlag;
});
}),
new Text(
widget.title,
style: new TextStyle(fontWeight: FontWeight.bold, color: Colors.white),
)
],
),
),
new ExpandableContainer(
expanded: expandFlag,
child: new ListView.builder(
itemBuilder: (BuildContext context, int index) {
return new Container(
decoration:
new BoxDecoration(border: new Border.all(width: 1.0, color: Colors.grey), color: Colors.black),
child: new ListTile(
title: new Text(
"Cool $index",
style: new TextStyle(fontWeight: FontWeight.bold, color: Colors.white),
),
leading: new Icon(
Icons.local_pizza,
color: Colors.white,
),
),
);
},
itemCount: 15,
))
],
),
);
}
}
class ExpandableContainer extends StatelessWidget {
final bool expanded;
final double collapsedHeight;
final double expandedHeight;
final Widget child;
ExpandableContainer({
@required this.child,
this.collapsedHeight = 0.0,
this.expandedHeight = 300.0,
this.expanded = true,
});
@override
Widget build(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width;
return new AnimatedContainer(
duration: new Duration(milliseconds: 500),
curve: Curves.easeInOut,
width: screenWidth,
height: expanded ? expandedHeight : collapsedHeight,
child: new Container(
child: child,
decoration: new BoxDecoration(border: new Border.all(width: 1.0, color: Colors.blue)),
),
);
}
}
预先感谢
答案 0 :(得分:0)
如果您想坚持这种方法,您可以将 Home 配置为 StatefulWidget 来管理 ListView 项目的展开/收回状态。为了只让被点击的小部件执行展开/收回操作,我们需要跟踪哪个列表项被点击。
ListView.builder(
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTap: () {
debugPrint('List item $index tapped $expand');
setState(() {
/// XOR operand returns when either or both conditions are true
/// `tapped == null` on initial app start, [tapped] is null
/// `index == tapped` initiate action only on tapped item
/// `!expand` should check previous expand action
expand = ((tapped == null) || ((index == tapped) || !expand)) ? !expand : expand;
/// This tracks which index was tapped
tapped = index;
debugPrint('current expand state: $expand');
});
},
/// We set ExpandableListView to be a Widget
/// for Home StatefulWidget to be able to manage
/// ExpandableListView expand/retract actions
child: expandableListView(
index,
"Title $index",
index == tapped? expand: false,
),
);
}
)
完整代码
void main() {
runApp(MaterialApp(home: Home()));
}
class Home extends StatefulWidget {
@override
createState() => HomeState();
}
class HomeState extends State<Home> {
bool expand = false;
int? tapped;
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey,
appBar: AppBar(
title: Text("Expandable List"),
backgroundColor: Colors.redAccent,
),
body: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTap: () {
debugPrint('List item $index tapped $expand');
setState(() {
/// XOR operand returns when either or both conditions are true
/// `tapped == null` on initial app start, [tapped] is null
/// `index == tapped` initiate action only on tapped item
/// `!expand` should check previous expand action
expand = ((tapped == null) || ((index == tapped) || !expand)) ? !expand : expand;
/// This tracks which index was tapped
tapped = index;
debugPrint('current expand state: $expand');
});
},
/// We set ExpandableListView to be a Widget
/// for Home StatefulWidget to be able to manage
/// ExpandableListView expand/retract actions
child: expandableListView(
index,
"Title $index",
index == tapped? expand: false,
),
// child: ExpandableListView(
// title: "Title $index",
// isExpanded: expand,
// ),
);
},
itemCount: 5,
),
);
}
Widget expandableListView(int index, String title, bool isExpanded) {
debugPrint('List item build $index $isExpanded');
return Container(
margin: EdgeInsets.symmetric(vertical: 1.0),
child: Column(
children: <Widget>[
Container(
color: Colors.blue,
padding: EdgeInsets.symmetric(horizontal: 5.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(
icon: Container(
height: 50.0,
width: 50.0,
decoration: BoxDecoration(
color: Colors.orange,
shape: BoxShape.circle,
),
child: Center(
child: Icon(
isExpanded
? Icons.keyboard_arrow_up
: Icons.keyboard_arrow_down,
color: Colors.white,
size: 30.0,
),
),
),
onPressed: () {
// setState(() {
// expandFlag = !expandFlag;
// });
}),
Text(
title,
style: TextStyle(
fontWeight: FontWeight.bold, color: Colors.white),
)
],
),
),
ExpandableContainer(
expanded: isExpanded,
child: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return Container(
decoration: BoxDecoration(
border: Border.all(width: 1.0, color: Colors.grey),
color: Colors.black),
child: ListTile(
title: Text(
"Cool $index",
style: TextStyle(
fontWeight: FontWeight.bold, color: Colors.white),
),
leading: Icon(
Icons.local_pizza,
color: Colors.white,
),
),
);
},
itemCount: 15,
))
],
),
);
}
}
class ExpandableContainer extends StatelessWidget {
final bool expanded;
final double collapsedHeight;
final double expandedHeight;
final Widget child;
ExpandableContainer({
required this.child,
this.collapsedHeight = 0.0,
this.expandedHeight = 300.0,
this.expanded = true,
});
@override
Widget build(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width;
return AnimatedContainer(
duration: Duration(milliseconds: 500),
curve: Curves.easeInOut,
width: screenWidth,
height: expanded ? expandedHeight : collapsedHeight,
child: Container(
child: child,
decoration:
BoxDecoration(border: Border.all(width: 1.0, color: Colors.blue)),
),
);
}
}