Flutter ListView with nested ListView throws RangeError for offscreen widgets

huangapple go评论67阅读模式
英文:

Flutter ListView with nested ListView throws RangeError for offscreen widgets

问题

以下是翻译好的部分:

"First time working in Flutter and not really a software wizard. I've built an app that connects to Firebase and retrieves a data structure as a Map (all after login). This works fine. However, the data is (kind of) a list of lists (or Map of Maps), etc. Basic structure is:"

第一次在Flutter中工作,不是特别懂软件。我已经构建了一个应用程序,它连接到Firebase并在登录后检索一个数据结构作为Map。这部分运作正常。但是,数据有点像是一个列表的列表(或Map的Map),等等。基本结构如下:
{
    title1: {
        item-A: {
            0: line1,
            1: line2,
            2: line3,
        },
        item-B: {
            0: line1,
            1: line2,
            2: line3,
        }
    },
    title2: {
        item-A: {
            0: line1,
...
}

"The schema can have more or fewer titles, items, and lines, but the structure is the same."

模式可以有更多或更少的标题、项目和行,但结构是相同的。

"The code I've implemented gets the values from the database (Firebase Realtime Database) via FutureBuilder, formats the results, and displays them. Retrieving the results and the general display formatting works as intended, but I can only see one or two of the list widgets before a huge red box is displayed and I get the following error:"

我实现的代码从数据库(Firebase实时数据库)中获取值,使用FutureBuilder格式化结果并显示它们。检索结果和一般的显示格式化都按预期工作,但在显示一个或两个列表小部件之前,我只能看到一个巨大的红色框,并且出现以下错误:

"The following IndexError was thrown building:
RangeError (index): Index out of range: index should be less than 1: 1"

构建时引发了以下IndexError:
RangeError(索引):索引超出范围:索引应小于1:1

"If I run a Hot Refresh or Hot Reload, or just reload the browser, I get a few more rows of Widgets and the error changes to the next index increment:"

如果我运行热刷新(Hot Refresh)或热重新加载(Hot Reload),或只是重新加载浏览器,我会得到更多的小部件行,并且错误会更改到下一个索引增加:

"The following IndexError was thrown building:
RangeError (index): Index out of range: index should be less than 4: 5"

构建时引发了以下IndexError:
RangeError(索引):索引超出范围:索引应小于4:5

"If I keep refreshing, eventually the whole list shows up and the error goes away. Obviously this is not the desired behavior, however."

如果我继续刷新,最终整个列表会显示出来,错误会消失。显然,这不是期望的行为,然而。

"My code (with a couple of details left out) is as follows:"

我的代码(略去了一些细节)如下:

上述是您提供的内容的中文翻译。如果您需要进一步的帮助或有其他问题,请随时提出。

英文:

First time working in Flutter and not really a software wizard. I've built an app that connects to Firebase and retrieves a data structure as a Map (all after login). This works fine. However, the data is (kind of) a list of lists (or Map of Maps), etc. Basic structure is:

{
title1: {
      item-A: {
               0: line1,
               1: line2,
               2: line3,
              },
      item-B: {
               0: line1,
               1: line2,
               2: line3,
              }
        },
title2: {
      item-A: {
               0: line1,
...
}

The schema can have more or fewer titles, items, and lines, but the structure is the same.

The code I've implemented gets the values from the database (Firebase Realtime Database) via FutureBuilder, formats the results, and displays them. Retrieving the results and the general display formatting works as intended, but I can only see one or two of the list widgets before a huge red box is displayed and I get the following error:

The following IndexError was thrown building:
RangeError (index): Index out of range: index should be less than 1: 1

If I run a Hot Refresh or Hot Reload, or just reload the browser, I get a few more rows of Widgets and the error changes to the next index increment:

The following IndexError was thrown building:
RangeError (index): Index out of range: index should be less than 4: 5

If I keep refreshing, eventually the whole list shows up and the error goes away. Obviously this is not the desired behavior, however. I've been working this and testing different approaches but I don't really understand what the issue is.

My code (with a couple of details left out) is as follows:

 Widget build(BuildContext context) {
    return Consumer<ApplicationState>(
        builder: (context, appState, child) {
          selectedIndex.add(-1);

          return Scaffold(
              ...
              body: FutureBuilder(
                future: futureDataRetreiverFunction(),
                builder: (BuildContext context, AsyncSnapshot<Map> snapshot) {

                if (snapshot.connectionState == ConnectionState.done && snapshot.hasData) {
                  ... // convert the snapshot.data here // 
                  return Container(
                      ...
                      child: ListView(
                          shrinkWrap: true,
                          children: [
                            Form(
                            key: _formKey,
                            child: Column(
                                children: [
                                  ListView.builder(
                                    scrollDirection: Axis.vertical,
                                    controller: ScrollController(),
                                    shrinkWrap: true,
                                    itemCount: snapshotData.keys.length, // the data is a Map
                                    itemBuilder: (BuildContext context, int index) =>
                                      Column(
                                          children: [
                                            ...
                                            Row(
                                              children: [
                                                Text(snapshotData.keys.elementAt(index)),
                                              ]
                                            ),
                                            Row(
                                              children: [
                                                Text(selectedIndex[index].toString())
                                              ]
                                            ),
                                            Row(
                                              children: [
                                              Flexible(
                                                fit: FlexFit.loose,
                                                child: Padding(
                                                  padding: const EdgeInsets.fromLTRB(5, 0, 0, 10),
                                                    child: ListView.builder(
                                                      shrinkWrap: true,
                                                      primary: false,
                                                      itemCount: snapshotData.values.elementAt(index)[1].length,
                                                      itemBuilder: (BuildContext context, int index2) =>
                                                        Text(snaptshotData.values.elementAt(index)[1][index2])
                                                    )
                                                  )
                                                )]
                                              )
                                            ])
                                           )
                                         ])
                                        ])
                                       );
...                                                  

答案1

得分: 1

Vishal在他对这个问题的第一个评论中指出了答案。我在setState({})调用中使用了"selectedIndex"来改变一些视觉效果,作为onTap: () {}调用的一部分。我之前在类的早期使用了一个简单的初始化调用来初始化列表(List selectedIndex = [];),但后来只在构建器中添加了一个项目到索引中。然而,在这种情况下,总共有6个项目被构建(在其他情况下可能更多/更少),这就引发了索引错误。这就是为什么在重新加载时索引会递增(另一个seletedIndex.add(-1);被调用)。我添加了一个快速函数,根据快照数据的大小来预先填充索引,代码如下:

for (var counter=0; counter<snapshotData.keys.length; counter++) {
    selectedIndex.add(-1);
}

这解决了索引RangeError。

英文:

Vishal pointed out the answer in his first comment to this question. I am using "selectedIndex" as part of a setState({}) call to change some visuals as part of an onTap: () {} call. I was initiating the list with a simple initiation call earlier in the class (List selectedIndex = [];), but then was only adding 1 item to the index in the builder. However, in this case, there are a total of 6 items which get built (more/less in other scenarios), and that was throwing the index error. Which is why it would increment on reload (another seletedIndex.add(-1); was called). I dropped in a quick function to pre-populate the index based on the size of the snapshot data, along the lines of:

for (var counter=0; counter<snapshotData.keys.length; counter++) {
    selectedIndex.add(-1);
}

This solved the index RangeError.

huangapple
  • 本文由 发表于 2023年2月19日 11:51:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/75497874.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定