I have an interface with a ListView
, each element has a PopupMenuButton
with an option, this option sends information to another screen
layout of the widget where thePopupMenuButton
class _PruebaPantallaState extends State<PruebaPantalla> {
int count = 0;
@override
Widget build(BuildContext context) {
print("6.-Pantalla prueba");
// TODO: implement build
return Scaffold(
body: getApidataList(),
);
}
FutureBuilder getApidataList() {
return FutureBuilder(
future: ApiService.getdataList(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
print("3.-Entrada (conexion establecida)");
final data = snapshot.data;
return ListView.separated(
separatorBuilder: (context, index) {
return Divider(
height: 2,
color: Colors.black,
);
},
itemBuilder: (context, index) {
return ListTile(
title: Text(
data[index]['dataTitulo'].toString(),
style: TextStyle(
color: Colors.black, fontWeight: FontWeight.bold),
),
subtitle: Text(data[index]['dataTextoBiblico'].toString()),
onTap: () {
datadb datadb =
datadb("", 0, 0, "", "", "", "", "", "", "", 0);
datadb.setdataId = data[index]["dataId"];
datadb.setdataTipo = data[index]["dataTipo"];
datadb.setdataNum = data[index]["dataNum"];
datadb.setdataNumMasc = data[index]["dataNumMasc"];
datadb.setdataTitulo = data[index]["dataTitulo"];
datadb.setdataContenido = data[index]["dataContenido"];
datadb.setdataPartitura = data[index]["dataPartitura"];
datadb.setdataTextPublic =
data[index]["dataTextoBiblico"];
datadb.setdataDatosPublic =
data[index]["dataDatosComplementarios"];
datadb.setdataNota = data[index]["dataNota"];
datadb.setdataFechaActualizacion =
data[index]["dataFechaActualizacion"];
datadb.setdataStatus = 1;
navigateToDetail(datadb);
},
trailing: PopupMenuButton<dynamic>(
onSelected: showMenuSelection,
itemBuilder: (context) => [
PopupMenuItem(
child: Text("Agregar a mis listas"),
value: data[index],
)
]),
);
},
itemCount: data.length,
);
}
return Center(
child: CircularProgressIndicator(),
);
},
);
}
void navigateToDetail(datadb data) async {
bool result =
await Navigator.push(context, MaterialPageRoute(builder: (context) {
return dataDetalle(todo: data);
}));
}
void showMenuSelection(dynamic value) async {
bool result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Play_List(value),
),
);
if (result) {
print('>>>>>>>>>>>>>>Mostrando SnackBar<<<<<<<<<<<<');
final snackBar = SnackBar(
content: Text('Se agrego correctamente a la lista'),
);
Scaffold.of(context).showSnackBar(snackBar);
print(
"Se agrego correctamente a la lista--------------------------------");
}
}
void updateListView() {
final Future<Database> dbFuture = databaseHelper.initializeDatabase();
dbFuture.then((databse) {
Future<List<datadb>> dataListFuture = databaseHelper.getdataList();
dataListFuture.then((dataList) {
setState(() {
this.dataList = dataList;
this.count = dataList.length;
});
});
});
}
}
This part is where you are redirected to another screen
trailing: PopupMenuButton<dynamic>(
onSelected: showMenuSelection,
itemBuilder: (context) => [
PopupMenuItem(
child: Text("Agregar a mis listas"),
value: data[index],
)
]),
MethodshowMenuSelection
Which is supposed to receive a type value on return bool
to display aSnackBar
void showMenuSelection(dynamic value) async {
bool result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Play_List(value),
),
);
if (result) {
final snackBar = SnackBar(
content: Text('Se agrego correctamente a la lista'),
);
setState(() {
Scaffold.of(context).showSnackBar(snackBar);
});
}
}
If I remove the setState
it sends me the following exception in the same way I try to use a showDialog
and it sends the same exception
_AssertionError ('package:flutter/src/material/scaffold.dart': Failed assertion: line 1184 pos 12: 'context != null': is not true.)
If I put the setState
it sends me the following exception
FlutterError (setState() called after dispose(): _PruebaPantallaState#d31fe(lifecycle state: defunct, not mounted) This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (eg, whose parent widget no longer includes the widget in its build).This error can occur when code calls setState() from a timer or an animation callback.The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback.Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object after it has been removed from the tree.To avoid memory leaks, consider breaking the reference to this object during dispose().)
To return after adding to the other interface I use the following method The method contains much more information but I don't think it is necessary to include it since the one that returns to the interface is only one line. In case all the information is required, I can add it.
void navigateToDetail(dynamic lista, BuildContext newContext) async {
Navigator.pop(context,true);
}
Ok, this case is a bit special, as you see here it is not necessary to use the method
Builder
to generate a new context since itFutureBuilder
already does that (apart from allowing us to work with Futures).Now, the problem is that you use the current context (of the FutureBuilder), to show the menu , and after selecting the menu, you go to another screen, at that moment, the context was lost and a new one was generated, but you stayed with the old context, hence the error.
To fix that we're going to have to use
GlobalKey
delScaffoldState
to get the reference to theScaffold
current one, and be able to display the SnackBar.So, you need to make these changes:
Add a variable that references the
ScaffoldState
Assign that key to the Scaffold
And finally use that key to get the state del
Scaffold
and display theSnackBar