我正在学习Flutter,是否有可能创建一个可重排序列表,其中包含的项目本身就是可重排序列表(下图)。如果有人可以建议我或帮助我,我将不胜感激。谢谢
这是我的代码
class _ReorderItemsState extends State<ReorderItems> {
List<String> topTen = [
"EPL",
"MLS",
"LLG",
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: ReorderableListView(
onReorder: onReorder,
children: getListItem(),
),
);
}
List<ExpansionTile> getListItem() => topTen.asMap()
.map((index, item) => MapEntry(index, buildTenableListTile(item, index)))
.values.toList();
ExpansionTile buildTenableListTile(String item, int index) => ExpansionTile(
key: ValueKey(item),
title: Text(item),
leading: Icon(Icons.list),
backgroundColor: Colors.blue,
);
void onReorder(int oldIndex, int newIndex){
if(newIndex > oldIndex){
newIndex -=1;
}
setState(() {
String game = topTen[oldIndex];
topTen.removeAt(oldIndex);
topTen.insert(newIndex, game);
});
}
}
答案 0 :(得分:1)
您可以通过设置children
小部件的ExpansionTile
属性来实现。
方法如下。
ChangeNotifier
或BLoc
的方法。但是,如果您更改父列表或子列表,则不需要,因为Flutter控件是不可变的,因此需要完全重建。/// Holding the common data as a singleton to avoid excessive rebuilds.
/// Usually this should be replaced with a manager or bloc or changenotifier class
class DataHolder {
List<String> parentKeys;
Map<String, List<String>> childMap;
DataHolder._privateConstructor();
static final DataHolder _dataHolder = DataHolder._privateConstructor();
static DataHolder get instance => _dataHolder;
factory DataHolder.initialize({@required parentKeys}) {
_dataHolder.parentKeys = parentKeys;
_dataHolder.childMap = {};
for (String key in parentKeys) {
_dataHolder.childMap.putIfAbsent(
key, () => ['${key}child_1', '${key}child_2', '${key}child_3']);
}
return _dataHolder;
}
}
ReorderableListView
的子级ScrollController
。例如ReorderList
小部件。它几乎与您编写的内容相同,除了我返回ListTile
而不是ExpansionTile
并设置了scrollController
属性。当前的稳定版本不具有此属性。因此,在此解决方案中,它包装有PrimaryScrollController
小部件,以避免重复使用scrollController。
class ReorderList extends StatefulWidget {
final String parentMapKey;
ReorderList({this.parentMapKey});
@override
_ReorderListState createState() => _ReorderListState();
}
class _ReorderListState extends State<ReorderList> {
@override
Widget build(BuildContext context) {
return PrimaryScrollController(
controller: ScrollController(),
child: ReorderableListView(
// scrollController: ScrollController(),
onReorder: onReorder,
children: DataHolder.instance.childMap[widget.parentMapKey]
.map(
(String child) => ListTile(
key: ValueKey(child),
leading: Icon(Icons.done_all),
title: Text(child),
),
)
.toList(),
),
);
}
void onReorder(int oldIndex, int newIndex) {
if (newIndex > oldIndex) {
newIndex -= 1;
}
List<String> children = DataHolder.instance.childMap[widget.parentMapKey];
String game = children[oldIndex];
children.removeAt(oldIndex);
children.insert(newIndex, game);
DataHolder.instance.childMap[widget.parentMapKey] = children;
// Need to set state to rebuild the children.
setState(() {});
}
}
ExpansionTile
小部件中,将此新小部件设置为children
之一。此子级和父级都是根据DataHolder
单例类的值构建的。
请注意,我将设置一个恒定的高度以避免布局冲突。您必须将其用于动态尺寸。
class ReorderItems extends StatefulWidget {
final List<String> topTen;
ReorderItems({this.topTen});
@override
_ReorderItemsState createState() => _ReorderItemsState();
}
class _ReorderItemsState extends State<ReorderItems> {
@override
void initState() {
super.initState();
// initialize the children for the Expansion tile
// This initialization can be replaced with any logic like network fetch or something else.
DataHolder.initialize(parentKeys: widget.topTen);
}
@override
Widget build(BuildContext context) {
return PrimaryScrollController(
key: ValueKey(widget.topTen.toString()),
controller: ScrollController(),
child: ReorderableListView(
onReorder: onReorder,
children: getListItem(),
),
);
}
List<ExpansionTile> getListItem() => DataHolder.instance.parentKeys
.asMap()
.map((index, item) => MapEntry(index, buildTenableListTile(item, index)))
.values
.toList();
ExpansionTile buildTenableListTile(String mapKey, int index) => ExpansionTile(
key: ValueKey(mapKey),
title: Text(mapKey),
leading: Icon(Icons.list),
backgroundColor: Colors.blue,
children: [
Container(
key: ValueKey('$mapKey$index'),
height: 400,
child: Container(
padding: EdgeInsets.only(left: 20.0),
child: ReorderList(
parentMapKey: mapKey,
),
),
),
],
);
void onReorder(int oldIndex, int newIndex) {
if (newIndex > oldIndex) {
newIndex -= 1;
}
setState(() {
String game = DataHolder.instance.parentKeys[oldIndex];
DataHolder.instance.parentKeys.removeAt(oldIndex);
DataHolder.instance.parentKeys.insert(newIndex, game);
});
}
}
此codepen中提供了一个完整的解决方案。
我更改了代码以从父窗口小部件动态接受项目列表。您将必须尝试如何维护数据并减少重建。但总的来说,只要列表保持不变,孩子ReorderableListView
就可以工作。
希望这会有所帮助。