简体   繁体   中英

Flutter : Change Theme Brightness from another Widget

I have 2 screen Login and Home to learning change Brightness in MaterialApp dynamic. I using 2 packages Hive and Provider Packages for helping me with my case.

Everything is fine , I can change value switch in Home Screen ,but the problem is value in MaterialApp not changed. I only see switch change but ThemeData not changed. If i hot restart it changed.

I'm mistake something ?

User Provider

class UserProvider with ChangeNotifier {
  final String boxName = "user_box";
  Future<void> changeThemeApp({@required UserModelHive userModelHive}) async {
    final hiveBox = Hive.box(boxName);
    final valueBox = userModelHive;
    await hiveBox.put("userSession", valueBox);
    notifyListeners();
  }
}

MyApp Widget

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  final appDir = await pathProvider.getApplicationDocumentsDirectory();
  Hive.init(appDir.path);
  Hive.registerAdapter(UserModelHiveAdapter(), 0);
  await Hive.openBox('user_box');
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final userBox = Hive.box('user_box');
    if (userBox.isEmpty) {
      return MaterialAppCustom(home: LoginProvider());
    } else {
      final UserModelHive userModelHive = userBox.get("userSession");
      print(userModelHive.isDarkMode.toString());
      return MaterialAppCustom(
        brightness:
            userModelHive.isDarkMode ? Brightness.dark : Brightness.light,
        home: HomeScreen(),
      );
    }
  }
}

class MaterialAppCustom extends StatelessWidget {
  final Widget home;
  final Brightness brightness;
  MaterialAppCustom({@required this.home, this.brightness});
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (_) => UserProvider(),
      child: MaterialApp(
        home: home,
        theme: ThemeData(brightness: brightness),
        routes: {
          LoginProvider.routeNamed: (ctx) => LoginProvider(),
          HomeScreen.routeNamed: (ctx) => HomeScreen(),
        },
      ),
    );
  }
}

Home Screen

class HomeScreen extends StatelessWidget {
  static const routeNamed = "home-screen";
  @override
  Widget build(BuildContext context) {
    final userProvider = Provider.of<UserProvider>(context);
    final UserModelHive userModelHive = Hive.box('user_box').get("userSession");
    return Scaffold(
      body: AppBar(
        actions: <Widget>[
          Switch(
            value: userModelHive.isDarkMode,
            onChanged: (value) {
              return userProvider.changeThemeApp(
                userModelHive: UserModelHive()
                  ..id = userModelHive.id
                  ..name = userModelHive.name
                  ..isDarkMode = value,
              );
            },
          ),
        ],
      ),
    );
  }
}

我的GIF

  1. Wrap your MaterialApp with WatchBoxBuilder Widget (it is in hive package).
  2. You should map your theme with enum, int or string value.
  3. Have a Hive box where you save the value for theme.
  4. Give that box to the WatchBoxBuilder that is wraped around Material Widget.
  5. Now whenever the value of theme is changed in the hive box your WatchBoxBuilder will rebuild and your theme will change from any part of your app.

Whenever you are using hive in widget tree you should only read values through WatchBoxBuilder . It has capability to rebuild your widget so that it can consume new values.

I hope this helps, in case of any doubt please comment.

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