简体   繁体   中英

ListView not rebuilding when returned to screen even after using setState()?

I have a list that is populated based on number of files in a folder. On application start it manages to build my list correctly and as expected.

But on the new note screen the user has the option to save a note in this folder. When I come back to this screen the list does not rebuild based on this new file added. When I close application and restart, the file shows up in my list.

Following this answer: is it possible to refresh or reload page with navigator.pop... like 1st (nav.push=>2) page to 2nd page and back from 2nd (nav.pop, value) to 1st page? I used .then() with Navigator.push and rebuilt my list in setState() but it still does not update.

What am I doing wrong? Below is my code:

class _HomeListViewState extends State<HomeListView> {
  Directory easyDir;
  var txtList;

  @override
  void initState(){
    super.initState();
    easyDir = Directory(widget.folderPath);
    buildTxtList();
  }

  void buildTxtList(){
    //list of paths of my txt files in the folder
    txtList = easyDir
        .listSync()
        .map((item) => item.path)
        .where((item) => item.endsWith(".txt"))
        .toList();
  }

  @override
  Widget build(BuildContext context) {

    print(txtList.length);
    
    return ListView.builder(
      itemCount: txtList.length,
      padding: EdgeInsets.all(10.0),
      itemBuilder: (context, index){
        File file = new File(txtList[index]);
        String name = file.path.split('/').last;
        return Card(
          color: (index % 2 == 0) ? Colors.grey.shade300 : Colors.white,
          shadowColor: Colors.teal,
          elevation: 7.0,
          child: ListTile(
            leading: Icon(Icons.assignment),
            title: Text(name),
            trailing: Icon(Icons.keyboard_arrow_right),
            onTap: () {
              Navigator.push(
                context,
                MaterialPageRoute(builder: (context) => NoteEditScreen(
                  txtPath: file.path,
                ),
                ),
              ).then((value) {
                setState(() {
                  buildTxtList();
                });
              });
            },
            onLongPress: () => print('list tile long pressed'),
          ),
        );
      },
    );
  }
}

One way to accomplish this is by passing a function to NoteEditScreen() that will fire a callback in the main screen to rebuild it(We can already use the buildTxtList function or create a new one only for it)

void buildTxtList() {
    txtList = easyDir
        .listSync()
        .map((item) => item.path)
        .where((item) => item.endsWith(".txt"))
        .toList();
    
    setState(() {}); // To rebuild the Widget
   
  }

Then pass it down

Navigator.push(
                context,
                MaterialPageRoute(builder: (context) => 
                  NoteEditScreen(onPressed: buildTxtList),
                ),
                   );

Then in the NoteEditScreen , first declare the property, lastly, in the AppBar call it.

NOTE: You don't have to call the function in the leading property of the AppBar, you can maybe call it when they are done saving the note in the folder.

final Function onPressed;
  
  NoteEditScreen({this.onPressed});

  appBar: AppBar(
      title: Text("Screen 2"),
       leading: IconButton(
        icon: Icon(Icons.arrow_back),
         onPressed: () {
           onPressed();
           Navigator.pop(context);
         }
       )
     ),

NOTE: You should definitely take a look at these two posts that talk about using setState(() {}) Empty set state what is the point?

Why does setState take a closure?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM