flutter - 在 Flutter 中展开 ExpansionTile 时从 API 加载子数据
问题描述
这个想法是,我有主要类别,它们有自己的 id,当用户展开图块(应该是 fetchFromApi)时,它将从 api 中获取数据(在本例中为模拟资产 json 文件)并显示它作为瓷砖。
我正在努力获得正确的机制来加载它。我想设置状态?我已经尝试过使用futurebuilder,因为我确实希望在加载时出现加载图标,但我似乎无法正确理解这个想法。关于如何实现这一点的建议将不胜感激。
这是我现在的课。
class DrawerNavigationPart extends StatelessWidget {
final List<Category> mainCategories = Categories.categoryData;
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: mainCategories.length,
itemBuilder: (BuildContext context, int index) {
final Category category = mainCategories[index];
if (category.fetchFromApi) {
List<Category> api = [];
return ExpansionTile(
key: PageStorageKey<Category>(category),
leading: Icon(category.icon),
title: Text(
category.title,
softWrap: false,
overflow: TextOverflow.ellipsis,
),
onExpansionChanged: (bool open) async {
if (open) {
String response = await DefaultAssetBundle.of(context)
.loadString(
'assets/822828-2228222-2222#category-api-mock.json');
api = categoryResponseFromJson(response).data;
print(api);
}
},
children: [
// FutureBuilder(
// future: DefaultAssetBundle.of(context).loadString(
// 'assets/822828-2228222-2222#category-api-mock.json'),
// builder: (context, snapshot) {
// final CategoryResponse categoryResponse =
// categoryResponseFromJson(snapshot.data);
//// return ListView.builder(
//// itemCount: 3,
//// itemBuilder: (BuildContext context, int index) {
//// return Text(index.toString());
//// });
// return ListTile(
// title: Text(categoryResponse.data[index].title));
// })
],
);
} else {
return ListTile(
leading: Icon(category.icon),
title: Text(
category.title,
softWrap: false,
overflow: TextOverflow.ellipsis,
),
onTap: () {
print(category.title + ' clicked');
},
);
}
},
);
}
Widget _buildTiles(Category root) {
if (root.children.isEmpty)
return ListTile(
leading: Icon(root.icon),
title: Text(
root.title,
softWrap: false,
overflow: TextOverflow.ellipsis,
),
onTap: () {
print("${root.title} listTile clicked");
},
);
return ExpansionTile(
key: PageStorageKey<Category>(root),
leading: Icon(root.icon),
title: Text(
root.title,
softWrap: false,
overflow: TextOverflow.ellipsis,
),
onExpansionChanged: (bool open) {
print("${root.title} expansionTile clicked $open");
},
children: root.children.map(_buildTiles).toList(),
);
}
}
解决方案
StatelessWidget 未更改视图
所以使用 StatefulWidget 和 State Class
例如
class DrawerNavigationPart extends StatefulWidget{
@override
State<StatefulWidget> createState() => _DrawerNavigationPart();
}
class _DrawerNavigationPart extends State<DrawerNavigationPart> {
final List<Category> mainCategories = Categories.categoryData;
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: mainCategories.length,
itemBuilder: (BuildContext context, int index) {
final Category category = mainCategories[index];
if (category.fetchFromApi) {
List<Category> api = [];
return ExpansionTile(
key: PageStorageKey<Category>(category),
leading: Icon(category.icon),
title: Text(
category.title,
softWrap: false,
overflow: TextOverflow.ellipsis,
),
onExpansionChanged: (bool open) async {
if (open) {
String response = await DefaultAssetBundle.of(context)
.loadString(
'assets/822828-2228222-2222#category-api-mock.json');
api = categoryResponseFromJson(response).data;
print(api);
}
},
children: [
FutureBuilder(
future: getJsonData(),
builder: (context, snapshot) {
final CategoryResponse categoryResponse =
categoryResponseFromJson(snapshot.data);
// return ListView.builder(
// itemCount: 3,
// itemBuilder: (BuildContext context, int index) {
// return Text(index.toString());
// });
return ListTile(
title: Text(categoryResponse.data[index].title));
})
],
);
} else {
return ListTile(
leading: Icon(category.icon),
title: Text(
category.title,
softWrap: false,
overflow: TextOverflow.ellipsis,
),
onTap: () {
print(category.title + ' clicked');
},
);
}
},
);
}
Widget _buildTiles(Category root) {
if (root.children.isEmpty)
return ListTile(
leading: Icon(root.icon),
title: Text(
root.title,
softWrap: false,
overflow: TextOverflow.ellipsis,
),
onTap: () {
print("${root.title} listTile clicked");
},
);
return ExpansionTile(
key: PageStorageKey<Category>(root),
leading: Icon(root.icon),
title: Text(
root.title,
softWrap: false,
overflow: TextOverflow.ellipsis,
),
onExpansionChanged: (bool open) {
print("${root.title} expansionTile clicked $open");
},
children: root.children.map(_buildTiles).toList(),
);
}
Future<String> getJsonData() async {
var str = await DefaultAssetBundle.of(context).loadString(
'assets/822828-2228222-2222#category-api-mock.json');
return str;
}
}
推荐阅读
- javascript - 单击html中的标签时如何打开新窗口
- java - 通过接口将值从适配器传递到另一个活动
- swiftui - 是否有绝对可用于 SwiftUI 的每个修饰符的列表?
- html - WordPress / Gravity Forms - 根据数字字段的值显示/隐藏 div
- c - *++a 和 ++*b 有什么区别?
- java - 部分读取/解析 JSON 文件数据 kotlin
- android - Android 11 中不支持的 MIME 类型
- javascript - PubNub - 发送“欢迎”连接消息
- spring-boot - 在招摇文档中没有为 post api 提供有效负载:spring boot 应用程序
- asp.net-mvc - 如何从 ASP.NET CORE 中的弹出模式正确触发模型验证