Flutter Listview.Builder inside bottom sheet 小部件未在加载时加载数据
Flutter Listview.Builder inside bottom sheet widget not loading data on load
下面的代码在底页加载时不显示任何数据。加载底表后,如果我在代码编辑器上执行保存操作,它就会加载数据。我在这里错过了什么?
我有一个使用按钮调用的底部表单小部件。
_showBottomSheet() {
showModalBottomSheet(
context: context,
builder: (context) {
return const Contacts();
},
);
}
上面的代码加载了下面有一个 Listview.builder 的联系人小部件。
class Contacts extends StatefulWidget {
const Contacts({Key? key}) : super(key: key);
@override
_ContactsState createState() => _ContactsState();
}
class _ContactsState extends State<Contacts> {
List<PhoneBookContact> phoneBookContacts1 = [];
List<PhoneBookContact> phoneBookContacts2 = [];
@override
void initState() {
loadContacts();
super.initState();
}
Future loadContacts() async {
///somecode to gather data for the listview builder
///populates the phoneBookContacts1 & phoneBookContacts2 lists
}
@override
Widget build(BuildContext context) {
return Column(children: [
const Text('Contacts Set 1'),
displayPhoneBookContacts(phoneBookContacts1),
const Text('Contacts Set 2'),
displayPhoneBookContacts(phoneBookContacts2),
]);
}
Widget displayPhoneBookContacts(phoneBookContacts) {
return Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: phoneBookContacts.length,
itemBuilder: (BuildContext context, int index) {
return Card(
margin: const EdgeInsets.all(10),
child: ListTile(
contentPadding: const EdgeInsets.all(10),
title: Column(
children: [
Text(phoneBookContacts[index].phoneBookContact.toString()),
const SizedBox(
height: 20,
),
ListView.separated(
physics: const ClampingScrollPhysics(),
shrinkWrap: true,
itemCount: phoneBookContacts[index].contactNumbers!.length,
separatorBuilder: (BuildContext context, int index) =>
const Divider(),
itemBuilder: (BuildContext context, int phoneIndex) {
return InkWell(
onTap: () {},
child: Row(
children: [
Text(phoneBookContacts[index]
.contactNumbers![phoneIndex]
.phone),
],
),
);
},
),
],
),
),
);
},
),
);
}
}
因为函数 initState()
不等待您的 loadContacts()
,数据在函数 build()
之后加载。
您需要使用 FutureBuilder class 在加载数据后重建 ListView 小部件
示例:
FutureBuilder(
future: loadContacts(),
builder:(context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return Center(child: CircularProgressIndicator());
} else {
return Container(
child: ListView.builder(
itemCount: _faouriteList.length,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
return Text('${_faouriteList[index].title}');
}
)
);
}
}
)
我不喜欢在 StatefulWidget
中使用 FutureBuilder
,它会在每个 setState
上调用 API(future
)。至于注释,它在初始化数据后丢失 setState
。
@override
void initState() {
super.initState();
loadContacts();
}
Future loadContacts() async {
///somecode to gather data for the listview builder
///populates the phoneBookContacts1 & phoneBookContacts2
if(mounted){
// if widget build then setState call.if not we don't need to call setState
// for every initstate data loading, we have to ensure it if widget is build or not. most of the case user close screen when data loading, then error happens
setState(() {});// make sure to call setState
}
}
下面的代码在底页加载时不显示任何数据。加载底表后,如果我在代码编辑器上执行保存操作,它就会加载数据。我在这里错过了什么?
我有一个使用按钮调用的底部表单小部件。
_showBottomSheet() {
showModalBottomSheet(
context: context,
builder: (context) {
return const Contacts();
},
);
}
上面的代码加载了下面有一个 Listview.builder 的联系人小部件。
class Contacts extends StatefulWidget {
const Contacts({Key? key}) : super(key: key);
@override
_ContactsState createState() => _ContactsState();
}
class _ContactsState extends State<Contacts> {
List<PhoneBookContact> phoneBookContacts1 = [];
List<PhoneBookContact> phoneBookContacts2 = [];
@override
void initState() {
loadContacts();
super.initState();
}
Future loadContacts() async {
///somecode to gather data for the listview builder
///populates the phoneBookContacts1 & phoneBookContacts2 lists
}
@override
Widget build(BuildContext context) {
return Column(children: [
const Text('Contacts Set 1'),
displayPhoneBookContacts(phoneBookContacts1),
const Text('Contacts Set 2'),
displayPhoneBookContacts(phoneBookContacts2),
]);
}
Widget displayPhoneBookContacts(phoneBookContacts) {
return Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: phoneBookContacts.length,
itemBuilder: (BuildContext context, int index) {
return Card(
margin: const EdgeInsets.all(10),
child: ListTile(
contentPadding: const EdgeInsets.all(10),
title: Column(
children: [
Text(phoneBookContacts[index].phoneBookContact.toString()),
const SizedBox(
height: 20,
),
ListView.separated(
physics: const ClampingScrollPhysics(),
shrinkWrap: true,
itemCount: phoneBookContacts[index].contactNumbers!.length,
separatorBuilder: (BuildContext context, int index) =>
const Divider(),
itemBuilder: (BuildContext context, int phoneIndex) {
return InkWell(
onTap: () {},
child: Row(
children: [
Text(phoneBookContacts[index]
.contactNumbers![phoneIndex]
.phone),
],
),
);
},
),
],
),
),
);
},
),
);
}
}
因为函数 initState()
不等待您的 loadContacts()
,数据在函数 build()
之后加载。
您需要使用 FutureBuilder class 在加载数据后重建 ListView 小部件
示例:
FutureBuilder(
future: loadContacts(),
builder:(context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return Center(child: CircularProgressIndicator());
} else {
return Container(
child: ListView.builder(
itemCount: _faouriteList.length,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
return Text('${_faouriteList[index].title}');
}
)
);
}
}
)
我不喜欢在 StatefulWidget
中使用 FutureBuilder
,它会在每个 setState
上调用 API(future
)。至于注释,它在初始化数据后丢失 setState
。
@override
void initState() {
super.initState();
loadContacts();
}
Future loadContacts() async {
///somecode to gather data for the listview builder
///populates the phoneBookContacts1 & phoneBookContacts2
if(mounted){
// if widget build then setState call.if not we don't need to call setState
// for every initstate data loading, we have to ensure it if widget is build or not. most of the case user close screen when data loading, then error happens
setState(() {});// make sure to call setState
}
}