Force widget rebuild from drawer in Flutter

98 views Asked by At

I have a flutter app with drawer navigation. When open, the drawer is overlapping a widget (let's call it Screen_1).

I would like to force the Screen_1 rebuild when the user dismisses the drawer. What is the best way to do it? Thanks.

EDIT. A specific example: In the drawer the user can change their picture. But when they dismiss the drawer (eg by clicking outside of it), Screen_1 still shows their old picture. I'd like Screen_1 to show the new picture.

2

There are 2 answers

8
Arevan Shamal On

I have a few suggestions that might help you and you can choose based on your need and u can look into these:

ValueNotifier : https://api.flutter.dev/flutter/foundation/ValueNotifier-class.html

If you are pressing a button to close it you can use: Navigator.pushReplacement

Or lastly callback function

example:

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: HomeScreen(),
        );
      }
    }
    
    class HomeScreen extends StatelessWidget {
      void _rebuildScreen1(BuildContext context) {
        Navigator.pop(context); // Close the drawer
        Navigator.pushReplacement(
          context,
          MaterialPageRoute(
            builder: (context) => Screen_1(rebuildCallback: _rebuildScreen1),
          ),
        );
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Drawer Example'),
          ),
          drawer: Drawer(
            child: ListTile(
              title: Text('Close Drawer'),
              onTap: () => _rebuildScreen1(context), // Call the rebuild callback
            ),
          ),
          body: Screen_1(rebuildCallback: _rebuildScreen1),
        );
      }
    }
    
    class Screen_1 extends StatefulWidget {
      final VoidCallback rebuildCallback;
    
      Screen_1({required this.rebuildCallback});
    
      @override
      _Screen_1State createState() => _Screen_1State();
    }
    
    class _Screen_1State extends State<Screen_1> {
      @override
      Widget build(BuildContext context) {
        return Center(
          child: TextButton(
            onPressed: () => widget.rebuildCallback(), // Use the rebuild callback
            child: Text('Rebuild Screen 1'),
          ),
        );
      }
    }

0
Arevan Shamal On

First this is my user/authentication class and i user change ChangeNotifier so i can notify widget when needed to rebuild with the new data also i use setProfilePicture() to update the data and call notifyListeners():

    class UserAuthentication with ChangeNotifier {// added with ChangeNotifier
      final FirebaseAuth _auth = FirebaseAuth.instance;
      final FirebaseFirestore _firestore = FirebaseFirestore.instance;
      final FirebaseStorage _storage = FirebaseStorage.instance;
    
      String? _verificationId;
      static Student? _student;
    
      User? get user => _auth.currentUser;
      bool get isLoggedIn => _auth.currentUser != null;
        Future<void> setProfilePicture(File img) async {
        final String fileName =
            'profilePics/${user!.uid}.png'; // Using user ID as the file name
    
        // Attempt to delete the existing profile picture, if there is one
        FirebaseStorage.instance.ref(fileName).delete().catchError((error) {
          // You can ignore the error if you don't want to do anything when the file doesn't exist
        });
    
        // Upload the new profile picture
        final UploadTask task = FirebaseStorage.instance.ref(fileName).putFile(img);
    
        // Once the upload completes, get the download URL
        final TaskSnapshot snapshot = await task;
        final String downloadUrl = await snapshot.ref.getDownloadURL();
    
        // Update the photo URL for the user
        await user!.updatePhotoURL(downloadUrl); //updating user object
        notifyListeners(); //added this to notify listeners
      }
    }

so if i want a widget to be rebuild i will do this by using Consumer:


    Consumer<UserAuthentication>( // consumer will listen for changes and rebuilds when needed
                      builder: (context, value, _) {
                        return SizedBox(
                          width: 100.w, 
                          child: CircleAvatar(
                            radius: 50.r, 
                            backgroundImage: NetworkImage(
                              value.user == null
                                  ? 'https://www.gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50?r=pg'
                                  : value.user!.photoURL ??
                                      'https://www.gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50?r=pg', // Replace with your image URL
                            ),
                          ),
                        );
                      },
                    ),

dont forget that you need to add the provider in main like this:

    MultiProvider(
          providers: [
            ChangeNotifierProvider(create: (_) => UserAuthentication()),    
          ],