【问题标题】:RangeError in PageView inside a ListViewListView 内 PageView 中的 RangeError
【发布时间】:2021-11-19 15:19:59
【问题描述】:

在我最后一个问题之后 Adding elements to List 我正在尝试使用创建的 PostMedia 项填充 PageView。

这里有我的 StreamBuilder 的完整代码:

    StreamBuilder<List<Post>>(
        stream: postsProvider.posts,
        builder: (context, snapshot) {
          if (snapshot.data != null &&
              snapshot.data.isNotEmpty &&
              ConnectionState.done != null) {
            List<Post> listaInicial = snapshot.data;
            List<Post> listaFiltrada = [];
            listaFiltrada = listaInicial;

            return Padding(
              padding: const EdgeInsets.all(0.0),
              child: SizedBox(
                width: MediaQuery.of(context).size.width,
                height: MediaQuery.of(context).size.height - 140,
                child: ListView.builder(
                    itemCount: listaFiltrada.length,
                    itemBuilder: (context, indexPost) {
                      bool es_ambassador =
                          listaFiltrada[indexPost].post_autor_is_ambassador;

                      //ver si el post tiene media
                      bool tiene_media =
                          listaFiltrada[indexPost].post_tiene_media;

                      bool tiene_fotos =
                          listaFiltrada[indexPost].post_tiene_fotos;

                      List<List<PostMedia>> lista_medios;
                      lista_medios = [];
                      if (tiene_fotos) {
                        //foto 1
                        var foto1 = listaFiltrada[indexPost].foto_1;
                        //incluimos foto1 en la lista
                        List<PostMedia> lista1 = [
                          PostMedia(
                              media_url: foto1,
                              es_foto: true,
                              es_video: false,
                              es_youtube: false)
                        ];
                        lista_medios.add(lista1);


                        var foto2 = listaFiltrada[indexPost].foto_2;

                        if (foto2.isEmpty) {
                        } else {
                          //incluimos foto1 en la lista
                          List<PostMedia> lista2 = [
                            PostMedia(
                                media_url: foto2,
                                es_foto: true,
                                es_video: false,
                                es_youtube: false)
                          ];
                          lista_medios.add(lista2);

                        }
                        var foto3 = listaFiltrada[indexPost].foto_3;

                        if (foto3.isEmpty) {
                        } else {
                          //incluimos foto1 en la lista
                          List<PostMedia> lista3 = [
                            PostMedia(
                                media_url: foto3,
                                es_foto: true,
                                es_video: false,
                                es_youtube: false)
                          ];
                          lista_medios.add(lista3);
                          print("lISTA3:" +
                              lista_medios.length.toString());
                        }
                        var foto4 = listaFiltrada[indexPost].foto_4;

                        if (foto4.isEmpty) {
                        } else {
                          //incluimos foto1 en la lista
                          List<PostMedia> lista4 = [
                            PostMedia(
                                media_url: foto1,
                                es_foto: true,
                                es_video: false,
                                es_youtube: false)
                          ];
                          lista_medios.add(lista4);
                          print("lISTA4:" +
                              lista_medios.length.toString());
                        }
                        var foto5 = listaFiltrada[indexPost].foto_5;

                        if (foto5.isEmpty) {
                        } else {
                          //incluimos foto1 en la lista
                          List<PostMedia> lista5 = [
                            PostMedia(
                                media_url: foto5,
                                es_foto: true,
                                es_video: false,
                                es_youtube: false)
                          ];
                          lista_medios.add(lista5);

                        }
                      }

                      var texto = listaFiltrada[indexPost].post_texto;
                      bool es_mipost = false;

                      var id_autor = listaFiltrada[indexPost].post_autor_id;
                      if (id_autor == _miId) {
                        es_mipost = true;
                      } else {
                        es_mipost = false;
                      }

                      bool estadenunciado =
                          listaFiltrada[indexPost].post_denunciado;

                      Timestamp recibida =
                          listaFiltrada[indexPost].post_fecha;

                      var fecha_recibida = "....";
                      if (recibida == null) {
                      } else {
                        DateTime date = DateTime.parse(
                            recibida.toDate().toString());

                        fecha_recibida =
                            DateFormat('yyyy-MM-dd HH:mm', "en")
                                .format(date);
                        fecha_recibida =
                            tiempoDesdeFecha(fecha_recibida);
                      }

                      return Padding(
                        padding:
                            const EdgeInsets.only(bottom: 2.0, top: 6),
                        child: Card(
                          elevation: 10,
                          margin: EdgeInsets.only(left: 0, right: 0),
                          child: Column(children: [
                            Row(
                              children: [
                                Column(
                                  children: [
                                    Padding(
                                      padding:
                                          const EdgeInsets.all(8.0),
                                      child: Container(
                                        width: 60,
                                        height: 60,
                                        color: Colors.transparent,
                                        child: Stack(children: [
                                          CircleAvatar(
                                            radius: 31,
                                            backgroundColor:
                                                Colors.black,
                                            child: CircleAvatar(
                                              radius: 28.0,
                                              backgroundImage: NetworkImage(
                                                  listaFiltrada[indexPost]
                                                      .post_autor_avatar),
                                              backgroundColor:
                                                  Colors.transparent,
                                            ),
                                          ),
                                          //si es ambassador el autor del post
                                          es_ambassador
                                              ? Positioned(
                                                  right: 0,
                                                  bottom: 2,
                                                  child: Container(
                                                      height: 24,
                                                      width: 24,
                                                      child: Image(
                                                          image: AssetImage(
                                                              "assets/images/home_ambassador.png"))),
                                                )
                                              : Container(),
                                        ]),
                                      ),
                                    ),
                                  ],
                                ),
                                Column(
                                  crossAxisAlignment:
                                      CrossAxisAlignment.start,
                                  mainAxisAlignment:
                                      MainAxisAlignment.start,
                                  children: [
                                    Text(
                                      listaFiltrada[indexPost]
                                          .post_autor_nombre,
                                      style: TextStyle(
                                          fontWeight: FontWeight.bold,
                                          fontSize: 18),
                                    ),
                                    Text(
                                      fecha_recibida,
                                      style: TextStyle(fontSize: 10),
                                    ),
                                    Text(""),
                                    Text(""),
                                  ],
                                ),
                                Spacer(),
                                //si es mi post
                                es_mipost
                                    ? PopupMenuButton(
                                        icon: Icon(
                                          Icons.more_vert,
                                          size: 36,
                                        ), //don't specify icon if you want 3 dot menu
                                        color: AppColors.rojoMovMap,
                                        itemBuilder: (context) => [
                                              PopupMenuItem<int>(
                                                value: 2,
                                                child: Row(
                                                  mainAxisAlignment:
                                                      MainAxisAlignment
                                                          .spaceEvenly,
                                                  children: [
                                                    Text(
                                                      "Borrar post",
                                                      style: TextStyle(
                                                          fontWeight:
                                                              FontWeight
                                                                  .bold,
                                                          fontSize: 16,
                                                          color: Colors
                                                              .white),
                                                    ),
                                                    Icon(Icons.delete,
                                                        color: Colors
                                                            .white,
                                                        size: 30),
                                                  ],
                                                ),
                                              ),
                                            ],
                                        onSelected: (int indexx) async {
                                          showConfirmacionBorradoPost(
                                              context,
                                              listaFiltrada[indexPost]
                                                  .post_id);
                                        })
                                    : PopupMenuButton(
                                        icon: Icon(
                                          Icons.more_vert,
                                          size: 36,
                                        ), //don't specify icon if you want 3 dot menu
                                        color: AppColors.rojoMovMap,
                                        itemBuilder: (context) => [
                                              PopupMenuItem<int>(
                                                value: 1,
                                                child: Row(
                                                  mainAxisAlignment:
                                                      MainAxisAlignment
                                                          .spaceEvenly,
                                                  children: [
                                                    !estadenunciado
                                                        ? Text(
                                                            "denunciar",
                                                            style: TextStyle(
                                                                color: Colors
                                                                    .white),
                                                          )
                                                        : Text(
                                                            "ya denunciado",
                                                            style: TextStyle(
                                                                fontSize:
                                                                    14,
                                                                fontWeight:
                                                                    FontWeight
                                                                        .bold,
                                                                color: Colors
                                                                    .white),
                                                          ),
                                                    !estadenunciado
                                                        ? Icon(
                                                            Icons
                                                                .local_police_outlined,
                                                            color: Colors
                                                                .white,
                                                            size: 30)
                                                        : Icon(
                                                            Icons
                                                                .local_police_outlined,
                                                            color: Colors
                                                                .white,
                                                            size: 30),
                                                  ],
                                                ),
                                              ),
                                            ],
                                        onSelected: (int indexx) async {
                                          var postADenunciar =
                                              listaFiltrada[indexPost]
                                                  .post_id;

                                          PostCrud().denunciarPost(
                                              postADenunciar);

                                          Fluttertoast.showToast(
                                              msg:
                                                  'has denunciado el post actual',
                                              toastLength:
                                                  Toast.LENGTH_SHORT,
                                              gravity:
                                                  ToastGravity.CENTER,
                                              timeInSecForIosWeb: 2,
                                              backgroundColor:
                                                  Colors.red,
                                              textColor: Colors.white,
                                              fontSize: 16.0);

                                          DateTime now =
                                              new DateTime.now();
                                          DateTime date = new DateTime(
                                              now.year,
                                              now.month,
                                              now.day,
                                              now.hour,
                                              now.minute,
                                              now.second);
                                          String fecha_denuncia = date
                                                  .day
                                                  .toString() +
                                              "-" +
                                              date.month.toString() +
                                              "-" +
                                              date.year.toString() +
                                              " " +
                                              date.hour.toString() +
                                              ":" +
                                              date.minute.toString() +
                                              ":" +
                                              date.second.toString();

                                          PostCrud().crearDenunciaPost(
                                              postADenunciar,
                                              _miId,
                                              fecha_denuncia);
                                        }),

                                //si no es mi post
                              ],
                            ),
                            Row(
                              mainAxisAlignment:
                                  MainAxisAlignment.start,
                              children: [
                                Padding(
                                  padding: const EdgeInsets.all(0.0),
                                  child: Container(
                                    width: MediaQuery.of(context)
                                        .size
                                        .width,
                                    child: Column(
                                      crossAxisAlignment:
                                          CrossAxisAlignment.start,
                                      children: [
                                        Padding(
                                          padding:
                                              const EdgeInsets.all(8.0),
                                          child: ReadMoreText(
                                            texto,
                                            trimLines: 1,
                                            trimMode: TrimMode.Line,
                                            trimCollapsedText:
                                                "leer mas",
                                            trimExpandedText:
                                                'leer menos',
                                          ),
                                        ),

                                        //si tiene media => mostrar el container, si no tiene media mostrar container en blanco
                                        tiene_media
                                            ? Container(
                                                color: Colors.black,
                                                height: 200,
                                                width: MediaQuery.of(
                                                        context)
                                                    .size
                                                    .width,
                                                child: PageView.builder(
                                                    itemCount:
                                                        lista_medios
                                                            .length,
                                                    itemBuilder:
                                                        (BuildContext
                                                                context,
                                                            int indice) {
                                                      return GestureDetector(
                                                        onTap: () {


                                                        },
                                                        child:
                                                            Container(
                                                                margin:
                                                                    const EdgeInsets.all(
                                                                        0),
                                                                decoration:
                                                                    BoxDecoration(
                                                                  image:
                                                                      DecorationImage(
                                                                    image:
                                                                        NetworkImage(lista_medios[indice][indexPost].media_url),
                                                                    fit:
                                                                        BoxFit.cover,
                                                                  ),
                                                                )),
                                                      );
                                                    }))
                                            : Container(
                                                color: Colors.red,
                                              ),
                                      ],
                                    ),
                                  ),
                                ),
                              ],
                            ),
                          ]),
                        ),
                      );
                    }),
              ),
            );
          } else {
            return Container(
              height: 200,
              width: 200,
              child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    Image.asset("assets/images/download.png"),
                  ]),
            );
          }
        })

这里有页面截图:

PageView 工作正常,当前帖子有 4 张图片,显示在 pageView 中的每一页上滑动

在我的应用程序中,帖子根据创建日期时间排序,较新的帖子显示在帖子列表的顶部,然后较旧的帖子显示在最新的帖子下方。

在此应用状态下,所有帖子均正确显示和排序,但从 #2 到列表底部的帖子在此行的综合浏览量中出现错误:

 NetworkImage(lista_medios[indice][indexPost].media_url),

给定的错误是RangeError (index): Invalid value: Only valid value is 0: 1

【问题讨论】:

    标签: flutter dart


    【解决方案1】:

    lista_medios 的数据形状如下所示

    lista_medios = [
        [PostMedia()], // lista1
        [PostMedia()], // lista2
        [PostMedia()], // lista3
        [PostMedia()], // lista4
        [PostMedia()], // lista5
    ];
    

    您的lista_medios 可以在列表中包含0-5 个lista。而lista 总是有一个PostMedia

    使用时:

    NetworkImage(lista_medios[indice][indexPost].media_url)
    

    您遇到了一个错误,因为您可能有多个帖子,而indexPost 可能是大于 0 的任何值,这再次超过了始终只有一个元素的 lista 的大小。

    您的问题的解决方案

    虽然 NetworkImage(lista_medios[indice][0].media_url) 可以工作,但在这种情况下它是不必要的复杂数据。

    每个listaFiltrada 最多需要渲染 5 个媒体。所以你可以像下面这样简化形状(删除不必要的嵌套列表):

    // sample data shape for `lista_medios`:  [PostMedia(), PostMedia(), ...]
    List<PostMedia> lista_medios = [];
    if (!listaFiltrada[indexPost].foto_1.isEmpty) {
       lista_medios.add(PostMedia(
            media_url: listaFiltrada[indexPost].foto_1, 
            es_foto: true, 
            es_video: false, 
            es_youtube: false
        ));
    }
    
    if (!listaFiltrada[indexPost].foto_2.isEmpty) {
       lista_medios.add(PostMedia(
            media_url: listaFiltrada[indexPost].foto_2, 
            es_foto: true, 
            es_video: false, 
            es_youtube: false
        ));
    }
    
    // and so on...
    

    然后您可以将其与PageViewBuilder 一起使用,如下所示:

    return PageView.builder(
        itemCount: lista_medios.length,
        itemBuilder: (BuildContext context, int indice) {
            return Container(
                   child:  NetworkImage(lista_medios[indice].media_url)
           );
        }
    );
    

    【讨论】:

    • 非常感谢您的努力和时间。我可以接受你的回答,但@Tanguy 是第一个给我同样解释的人
    • 不用担心。我在写答案时没有看到他的评论 :) 我打开浏览器并起草了一个答案,在完成我的答案之前我已经去做了一些事情。
    【解决方案2】:

    您正在填充一个二维列表 List&lt;List&lt;PostMedia&gt;&gt; lista_medios;

    当你只需要一个 List&lt;PostMedia&gt; lista_medios;

    这是因为您已经在构建帖子,从单个 indexPost 获取媒体,然后构建要显示的媒体列表。在您的示例中,嵌套列表中的元素永远不会超过一个,但会尝试使用 indexPost 访问多个元素。

    然后调用NetworkImage(lista_medios[indice].media_url), 应该可以工作。

    别忘了修改代码的其他部分:

    PostMedia media1 =
        PostMedia(
        media_url: foto1,
        es_foto: true,
        es_video: false,
        es_youtube: false);
    lista_medios.add(media1);
    

    您自己的解决方案正在运行,因为您总是获取嵌套列表的单个项目。为清楚起见,您根本不应该使用二维列表。

    【讨论】:

    • 非常感谢您的努力和时间。
    【解决方案3】:

    我找到了一个潜在的解决方案。在创建 PostMedia 列表时,它只在列表中创建一个项目,这意味着获取 PostMedia 项目的唯一方法是仅使用名为 indice 的索引:

     NetworkImage(lista_medios[indice][0].media_url)
    

    页面浏览仅显示来自 lista_medios 的元素,不需要 indexPost 索引。

    【讨论】:

      【解决方案4】:

      我认为您错误地使用了indice 而不是indexPost。像这样改变他们的立场,我认为它会起作用:

      image:
          NetworkImage(lista_medios[indexPost][indice].media_url),
      

      【讨论】:

      • 如果我按照您的建议更改索引的顺序,我将让所有项目正确显示其第一个媒体,但是在滑动浏览页面时,我再次遇到第一个错误。现在每个帖子有 5 个媒体,第一个媒体显示在每个帖子的浏览量上(ok),然后所有其他媒体抛出错误,第二个媒体=> RangeError(索引):无效值为 0:1,第三个媒体=> RangeError (index):无效值为0:2,第四媒体=> RangeError(index):无效值为0:4,第二媒体=> RangeError(index):无效值为0:4,
      猜你喜欢
      • 2014-10-19
      • 1970-01-01
      • 2021-11-23
      • 2021-11-08
      • 2021-08-16
      • 2023-03-25
      • 2021-08-24
      • 2021-03-31
      • 1970-01-01
      相关资源
      最近更新 更多