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
     }
  
}