Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change state of MaterialPageRoute?

Tags:

flutter

dart

I was following the tutorial from the Flutter docs where you create a Startup naming app. The app consists in two pages: one where there's an infinite list of randomly generated startup names that you can add to your favorites, and a favorites page where you can see the names you saved.

After completing the tutorial, I tried to add some functionality of my own, I wanted to be able to Unfavorite a name by tapping it on the "Favorites" page. Below is the code that pushes the Favorites page to the navigator:

    Navigator.of(context).push(
      MaterialPageRoute<void>(
        builder: (BuildContext context) {
          final Iterable<ListTile> tiles = _saved.map(
            (WordPair pair) {
              return ListTile(
                title: Text(
                  pair.asPascalCase, 
                  style: _biggerFont, 
                ),
                // Code I added // 
                trailing: Icon(Icons.delete), 
                onTap: () {
                  setState(() {
                    _saved.remove(pair);    
                  });
                },
                // End // 
              );
            },
          );
          final List<Widget> divided = ListTile
            .divideTiles(
              context: context,
              tiles: tiles,
            )
            .toList();

          return Scaffold(
            appBar: AppBar(
              title: Text('Saved suggestions'), 
            ),
            body: ListView(children: divided),
          );
        },
      ),
    );
  }

But it didn't worked as it should: you can indeed unsave names by tapping them, but the changes will only be shown on the screen after you go back to the main page and then to the favorites page again (or in other words, when Builder is called?).

So how do I fix this? Do I need to create a Stateful widget for the favorites page? If yes, how do I pass the _saved set to my new widget?

If anybody needs the whole code: https://pastebin.com/asLneaKe

like image 475
Allan Juan Avatar asked Sep 21 '25 01:09

Allan Juan


1 Answers

Wrap with StatefulBuilder works fine.
You can see full code and working demo

code snippet

MaterialPageRoute<void>(
        builder: (BuildContext context) {
          return StatefulBuilder(
              builder: (BuildContext context, StateSetter setState) {
            final Iterable<ListTile> tiles = _saved.map(

working demo

enter image description here

full code

import 'package:english_words/english_words.dart' as prefix0;
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Startup Name Generator',
      theme: ThemeData(
        primaryColor: Colors.white,
      ),
      home: RandomWords(),
    );
  }
}

class RandomWords extends StatefulWidget {
  @override
  RandomWordsState createState() => RandomWordsState();
}

class RandomWordsState extends State<RandomWords> {
  final List<WordPair> _suggestions = <WordPair>[];
  final Set<WordPair> _saved = Set<WordPair>();
  final TextStyle _biggerFont = const TextStyle(fontSize: 18.0);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Startup Name Generator'), actions: <Widget>[
        // Icone 3 linhas
        IconButton(
          icon: Icon(Icons.list),
          onPressed: _pushSaved,
        ),
      ]),
      body: _buildSuggestions(),
    );
  }

  Widget _buildRow(WordPair pair) {
    final bool alreadySaved = _saved.contains(pair);
    return ListTile(
        title: Text(
          pair.asPascalCase,
          style: _biggerFont,
        ),
        trailing: Icon(
          alreadySaved ? Icons.favorite : Icons.favorite_border,
          color: alreadySaved ? Colors.red : null,
        ),
        onTap: () {
          setState(() {
            if (alreadySaved) {
              _saved.remove(pair);
            } else {
              _saved.add(pair);
            }
          });
        });
  }

  Widget _buildSuggestions() {
    return ListView.builder(
      padding: const EdgeInsets.all(16.0),
      itemBuilder: (context, i) {
        if (i.isOdd) return Divider();

        final index = i ~/ 2;
        if (index >= _suggestions.length) {
          _suggestions.addAll(generateWordPairs().take(10));
        }
        return _buildRow(_suggestions[index]);
      },
    );
  }

  void _pushSaved() {
    Navigator.of(context).push(
      MaterialPageRoute<void>(
        builder: (BuildContext context) {
          return StatefulBuilder(
              builder: (BuildContext context, StateSetter setState) {
            final Iterable<ListTile> tiles = _saved.map(
              (WordPair pair) {
                return ListTile(
                  title: Text(
                    pair.asPascalCase,
                    style: _biggerFont,
                  ),
                  // Code I added //
                  trailing: Icon(Icons.delete),
                  onTap: () {
                    setState(() {
                      _saved.remove(pair);
                    });
                  },
                  // End //
                );
              },
            );
            final List<Widget> divided = ListTile.divideTiles(
              context: context,
              tiles: tiles,
            ).toList();

            return Scaffold(
              appBar: AppBar(
                title: Text('Saved suggestions'),
              ),
              body: ListView(children: divided),
            );
          });
        },
      ),
    );
  }
}
like image 79
chunhunghan Avatar answered Sep 23 '25 09:09

chunhunghan