1
votes

I have an app which has one base page which includes a ListTile of a number of different objects which is populated based on a global master list. If the user clicks on one of the ListTile tiles it navigates to a new page (second page) with specific information about the object. I also have left and right buttons which allow the user to navigate the global list without having to jump back to the main page. If the user sees an object they like, they can add it to their "saved" list which removes it from the global list of potential objects and adds it to the saved list instead. After they add the object I am using popUntil to return to the main page, however the "saved" object isn't removed. Based on reading the answer below I understand that perhaps my issue has to do with the fact that flutter doesn't recognize the change in the list and so it doesn't redraw the page. I saw one suggestion about adding a superfluous counter but couldn't figure out how to integrate it into my own popUntil implementation as this question is slightly simpler and doesn't use popUntil. What should I do to force the app to redraw the main page when i popUntil i get there?

Force Flutter navigator to reload state when popping

Here is the first page (Assume I named it route "Main" before I got here.)

final List<Object> _potentials = List<Object>();
final List<Object> _saved = List<Object>();

class MainPage extends StatefulWidget{
  @override
  _MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
@override
  build (BuildContext context) {
    final tiles = _potentials.map(
          (Object thing) {
        return ListTile(
          leading: Icon(Icons.person),
          title: Text(thing.name),
          onTap: () {
            selectedThing = thing;
            Navigator.of(context).push(
                MaterialPageRoute(
                    builder: (context) => SecondPage()
                )
            );
          },
        );
      },
    );
...    //there is more stuff here building out the tile views
  }
}

Here is the second page where the popUntil is

class SecondPage extends StatefulWidget{
  @override
  _SecondPageState createState() => _SecondPageState();
}
class _SecondPageState extends State<SecondPage>{
  @override
  build (BuildContext context) {
  return Scaffold(
  appBar: AppBar(
  title: Text(selectedThing.name),
  leading: IconButton(icon: Icon(Icons.arrow_back), onPressed: () {
    Navigator.popUntil(context, ModalRoute.withName('Main'));
  }),
  actions: [
  IconButton(icon: Icon(Icons.person_add), onPressed: (){
    _saved.add(selectedThing);
    _potentials.remove(selectedThing);
    Navigator.popUntil(context, ModalRoute.withName('Main'));
  } ),
  ],

  ),
... //more stuff here that isn't important
// (including the left and right navigation buttons which take you to a new second page and update selectedThing)
  }
}
1

1 Answers

0
votes

I don't fully understand your state managament or where do you save all the variables but one thing you could do is check if the _potentials or _saved changes. Navigator.pop returns a Future, even if Navigator.popUntil is void you can use this to your advantage with some async

onTap: () async {
 selectedThing = thing;
 final int length = _saved.length; //save a reference of the length of your list _saved
 await Navigator.of(context).push(
            MaterialPageRoute(
                builder: (context) => SecondPage()
            ); // await here until the popUntil from the second screen
 /*
 After the popUntil of the secondPage returns to this page it will run this next line (because the aync await future), 
 so if the user tap on the back arrow the list didn't change and the length are the same, 
 if he taps on the person_add Icon, you remove that object from _potentials and add it to _saved,
 so the lenght are different and it runs setState, forcing to rebuild MainPage.
 this.mounted is just for safety to make sure the MainPage is mounted in the tree and wasn't popped by mystake, 
 it's unsafe to call setState without being sure the state object is there
 */
 if(length != _saved.length && this.mounted) setState((){});
},

There are other ways to make sure the lists changed, using import 'package:collection/collection.dart'; with DeepCollectionEquality.unordered().equals(list1, list2); to check if the lists are the same or not