Reputation: 5101
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:
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
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
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
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
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