I'm trying to learn Flutter and I'm making my first app. Because of that I'm almost certain my question is dumb or very basic.
I have a very simple app that loads info from an API on the main page, it also has a button which redirects the user to a secondary config page or route. In this interface the user may select or deselect some items (this is very similar to the second part of the first flutter tutorial https://codelabs.developers.google.com/codelabs/first-flutter-app-pt2/#4 ). The problem I'm currently having is that when the user taps on some item, the icon doesn't change accordingly unless I hotReload the app in which case the icon shows as expected, meaning the rest of the logic is working more or less correctly. Im calling the setState method and I know it's calling the build widget yet the icons remain unchanged unless I hot reload the app.
I have implemented the pull to refresh functionality, this doesn't seem to work eihter. It doesn't update the data from the API, I need to go back to the main page and then enter again to the config no see the current data.
The question basically is ¿What needs to be done to refresh the "secondary route" when the user taps some element on it?
Part of the code used...
@override
Widget build(BuildContext context) {
print("corrió build");
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
actions: [
IconButton(onPressed: _irAConfig, icon: const Icon(Icons.settings))
],
),
body: FutureBuilder<List<Noticia>>(
future: futureNoticias,
builder: (context, snapshot) {
return RefreshIndicator(
child: _listViewNoticias(snapshot),
onRefresh: _pullRefreshNoticias,
);
},
),
);
}
void _irAConfig() {
futureSecciones = fuenteSecciones().getSecciones();
Navigator.of(context)
.push(MaterialPageRoute<void>(builder: (BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Secciones"),
),
body: FutureBuilder<List<Seccion>>(
future: futureSecciones,
builder: (BuildContext context, AsyncSnapshot ssSecciones) {
print("builder de irAConfig");
return RefreshIndicator(
child: _listViewSecciones(ssSecciones),
onRefresh: _pullRefreshSecciones,
);
},
),
);
}));
}
Widget _listViewSecciones(AsyncSnapshot ssSecciones) {
print("_listViewSecciones");
if (ssSecciones.hasData) {
return GroupedListView<dynamic, String>(
elements: ssSecciones.data,
groupBy: (element) => element.idPortal,
groupComparator: (value1, value2) => value1.compareTo(value2),
itemComparator: (item1, item2) =>
item1.descCategoria.compareTo(item2.descCategoria),
order: GroupedListOrder.ASC,
useStickyGroupSeparators: true,
groupSeparatorBuilder: (String value) => Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
value,
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
),
),
itemBuilder: (BuildContext c, element) {
return _buildRow(element);
},
);
} else {
return const Center(
child: Text("Cargando..."),
);
}
}
Widget _buildRow(Seccion seccion) {
print ("buildRow");
final alreadySaved = _saved.contains(seccion);
return Card(
elevation: 5.0,
margin: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)),
child: ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 10, vertical: 1),
//leading: Icon(Icons.account_circle),
title: Text(
seccion.descCategoria,
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.normal),
),
trailing: Icon(
alreadySaved ? Icons.check_box : Icons.check_box_outline_blank),
onTap: () {
setState(() {
if (alreadySaved) {
_saved.remove(seccion);
} else {
_saved.add(seccion);
}
});
},
),
);
}
CodePudding user response:
In case some is trying to figure this one out. Read this: https://flutter.dev/docs/development/ui/interactive#managing-state
Basically if you need the page to change, for instance as a result of user interaction, you need to use use StatefulWidget instead of Stateless...
CodePudding user response:
I am not sure about your code, but there might be a few reasons why icon is not changing:
- You are not calling
setState()
method after changing the variable value of that icon. - You put icon into wrong variable, and you are not passing it into build This is how you make some widget change its value:
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
void main() {
runApp(MaterialApp(home: Example()));
}
class Example extends StatefulWidget {
@override
State<Example> createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
IconData icon = 0;
changeIcon() {
icon = Icons.anotherIcon; // < == change icon
setState(); // < == call set state method
}
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: Center(
child: Icon(
icon
),
),
);
}
}
If you want to get a concrete answer, please, provide a simplified version of your code with all widget
related code included.