mvasco
mvasco

Reputation: 5101

RangeError in PageView inside a ListView

Following my last question at Adding elements to List I am trying to populate a PageView with the created PostMedia items.

Here you have the complete code for my 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"),
                  ]),
            );
          }
        })

Here you have a screenshot from the page:

enter image description here

The PageView is working fine, the current post has 4 images, that are shown in the pageView sliding on it on every page

In my app, the posts are ordered depending on their creation datetime, newer posts are shown on top of the list of posts and then the older posts are shown below the newest one.

At this app status, all posts are shown and ordered correctly, but the posts from #2 to the bottom of the list are getting an error at the pageview at this line:

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

the given error is RangeError (index): Invalid value: Only valid value is 0: 1

Upvotes: 1

Views: 200

Answers (4)

Turbo
Turbo

Reputation: 688

Your data shape looks like below for lista_medios

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

Your lista_medios can contain between 0-5 lista in the list. While lista always has one PostMedia.

When you use:

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

you got an error because you might have more than one post and indexPost might be any value greater than 0 which again exceed the size of your lista which always has one element.

Solution to your problem

While NetworkImage(lista_medios[indice][0].media_url) would work but it's unnecessary complicated data shaped in this case.

You need to render at most 5 medias from each listaFiltrada. So you can simplify the shape like below (Remove unnecessary nested list):

// 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...

Then you can use it with PageViewBuilder like below:

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

Upvotes: 0

Tanguy
Tanguy

Reputation: 984

You are populating a bi-dimensional list with List<List<PostMedia>> lista_medios;

When you just need a List<PostMedia> lista_medios;

This is because you're already building the post, fetching media at a single indexPost and then building a List of media to display. In your example you will never have more than one element in the nested list but try to access more than one with indexPost.

Then calling NetworkImage(lista_medios[indice].media_url), should work.

Don't forget to modify the other parts of your code :

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

Your own solution is working because you're always fetching the single item of the nested list. For clarity you should not use a bi-dimensional list at all.

Upvotes: 1

mvasco
mvasco

Reputation: 5101

I have found a potential solution. When creating the PostMedia list, it is only creating one item in the list, that means that the only way to get PostMedia items is using only the index called indice:

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

The pageview is only showing elements from lista_medios, the indexPost index is not needed.

Upvotes: 0

user16930239
user16930239

Reputation: 9788

I think you are using indice instead indexPost by mistake. change their positions like this and I think it will work:

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

Upvotes: 1

Related Questions