'How to reload the screen in flutter on alert dialog button press?

I'm making an app that shows images from a subreddit and I want to change these images based on the subreddit names entered through the alert dialog. I have implemented everything as follows but when I set the state, the images are not showing. How to fix this? Here is my code.

import 'package:flutter/material.dart';
import 'package:memes/screens/memes_screen.dart';

void main() {
  runApp(
    MaterialApp(
      debugShowCheckedModeBanner: false,
      home: HomePage(),
    )
  );
}

class HomePage extends StatefulWidget {
  const HomePage({ Key? key }) : super(key: key);

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {

  final TextEditingController textEditingController = TextEditingController();
  String subs = "memes";

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Color.fromARGB(255, 255, 254, 241), //Color(0xffdedede),

      appBar: AppBar(title: Text("Memes"), backgroundColor: Color(0xff008b00)),

      body: MemesScreen(subreddits: subs),

      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),

        backgroundColor: Color(0xff008b00),

        onPressed: (){
          _showDialog();
        },
      ),
    );
  }


  void _showDialog() {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        // return object of type Dialog
        return AlertDialog(

          backgroundColor: Color.fromARGB(255, 255, 254, 241),

          title: Text("Enter subreddits"),

          content: TextField(
            controller: textEditingController,
          ),
          
          actions: <Widget>[
            // usually buttons at the bottom of the dialog
            TextButton(
              child: new Text("Close", style: TextStyle(color: Color(0xff008b00))),
              onPressed: () {
                Navigator.of(context).pop();
              },
            ),

            TextButton(
              child: new Text("Get", style: TextStyle(color: Color(0xff008b00))),
              onPressed: () {
                String newSubs = textEditingController.text;
                setState(() {
                  subs = newSubs;
                });
                Navigator.of(context).pop();
              },
            ),
          ],
        );
      },
    );
  }
}

The string subs is passed to the MemesScreen that shows an image. If I change this subs value on a button press in _showDialog method and set the state, the screen is not reloading. How to fix this? Any help would be highly appreciated.



Solution 1:[1]

Wrap MemesScreen(subreddits: subs) INTO ValueListenableBuilder(). Then Put String subs variable in globals.dart page so that it can be changed on setState. Edit your Code as below

body: ValueListenableBuilder(
      valueListenable: refreshPage,
      builder: (context, value, child) {
        return MemesScreen(subreddits: subs);
      }),
     ......

Dialog page setState will be

  setState(() {
              subs = newSubs;
              refreshPage.value == 0
                  ? refreshPage.value = 1
                  : refreshPage.value = 0;
            });

globals.dart will be

import 'package:flutter/material.dart';

String subs = 'meme';
final refreshPage = ValueNotifier<int>(0);

Check this full code working and tested: main.dart

import 'package:answer_project/globals.dart';
import 'package:answer_project/meme_screen.dart';
import 'package:flutter/material.dart';

void main() {
 runApp(const MaterialApp(
 debugShowCheckedModeBanner: false,
 home: HomePage(),
 ));
 }

 class HomePage extends StatefulWidget {
 const HomePage({Key? key}) : super(key: key);

 @override
   State<HomePage> createState() => _HomePageState();
  }

  class _HomePageState extends State<HomePage> {
  final TextEditingController textEditingController = 
  TextEditingController();
  //String subs = "memes";

 @override
  Widget build(BuildContext context) {
  return Scaffold(
    backgroundColor:
      const Color.fromARGB(255, 255, 254, 241), //Color(0xffdedede),

  appBar: AppBar(
      title: const Text("Memes"), backgroundColor: const 
  Color(0xff008b00)),

  body: ValueListenableBuilder(
      valueListenable: refreshPage,
      builder: (context, value, child) {
        return MemesScreen(subreddits: subs);
      }),

  floatingActionButton: FloatingActionButton(
    child: const Icon(Icons.add),
    backgroundColor: const Color(0xff008b00),
    onPressed: () {
      _showDialog();
    },
  ),
  );
  }

  void _showDialog() {
  showDialog(
  context: context,
  builder: (BuildContext context) {
    // return object of type Dialog
    return AlertDialog(
      backgroundColor: const Color.fromARGB(255, 255, 254, 241),
      title: const Text("Enter subreddits"),
      content: TextField(
        controller: textEditingController,
      ),
      actions: <Widget>[
        // usually buttons at the bottom of the dialog
        TextButton(
          child: const Text("Close",
              style: TextStyle(color: Color(0xff008b00))),
          onPressed: () {
            Navigator.of(context).pop();
          },
        ),

        TextButton(
          child:
              const Text("Get", style: TextStyle(color: 
         Color(0xff008b00))),
          onPressed: () {
            String newSubs = textEditingController.text;
            setState(() {
              subs = newSubs;
              refreshPage.value == 0
                  ? refreshPage.value = 1
                  : refreshPage.value = 0;
            });
            Navigator.of(context).pop();
          },
        ),
      ],
    );
  },
  );
   }
  }

meme_screen.dart

  import 'package:flutter/material.dart';

class MemesScreen extends StatelessWidget {
const MemesScreen({Key? key, required this.subreddits}) : super(key: 
key);
final String subreddits;

@override
Widget build(BuildContext context) {
return Card(
  child: Text(
    subreddits,
  ),
);
}
}

globals.dart

  import 'package:flutter/material.dart';

  String subs = 'meme';

  final refreshPage = ValueNotifier<int>(0);

Another method of refreshing page is: use Navigator.pushReplacement() instead of Navigator.of(context).pop().

This is the code of _showDialog():

void _showDialog() {
showDialog(
 context: context,
 builder: (BuildContext context) {
 // return object of type Dialog
 return AlertDialog(
  backgroundColor: const Color.fromARGB(255, 255, 254, 241),
  title: const Text("Enter subreddits"),
  content: TextField(
    controller: textEditingController,
  ),
  actions: <Widget>[
    // usually buttons at the bottom of the dialog
    TextButton(
      child: const Text("Close",
          style: TextStyle(color: Color(0xff008b00))),
      onPressed: () {
        Navigator.of(context).pop();
      },
    ),

    TextButton(
      child:
          const Text("Get", style: TextStyle(color: 
     Color(0xff008b00))),
      onPressed: () {
        String newSubs = textEditingController.text;
        setState(() {
          subs = newSubs;
          refreshPage.value == 0
              ? refreshPage.value = 1
              : refreshPage.value = 0;
        });
        //Navigator.of(context).pop();
        Navigator.pushReplacement(context, MaterialPageRoute(builder: 
        (BuildContext context) => HomePage()));
      },
    ),
  ],
  );
 },
 );
  }

It will reload the HomePage. But the last stack was lost means you cannot go back on last page.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1