如何在Flutter中监听platformBrightness的变化?

15

我在搭建一个系统,当用户将系统主题更改为深色模式时,它可以更改主题。Flutter上表现良好!但是,当用户更改系统主题时,系统导航和状态栏不会更改其颜色。我在主页中的构建方法中运行了代码,但似乎不起作用。以下是主页构建方法中的代码:

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    Brightness sysBrightness = MediaQuery.of(context).platformBrightness;
    if (sysBrightness == Brightness.dark)
      Themes.setDarkSystemColors();
    else
      Themes.setLightSystemColors();

    return Scaffold(
      appBar: CustomAppBar(title: "Home"),
      drawer: CustomDrawer(),
      body: SizedBox(),
    );
  }
}

这是主应用程序中带有theme:darkTheme:的代码:

    return MaterialApp(
      initialRoute: '/',
      routes: routes,
      navigatorObservers: [_routeObserver],
      theme: Themes.lightTheme,
      darkTheme: Themes.darkTheme,
      debugShowCheckedModeBanner: false,
      title: 'School Life',
    );
6个回答

26
你可以用很多种方式来做这件事:
  • 使用 didChangeDependencies

    // 每次平台亮度变化时都会调用此回调函数。
    @override
    void didChangeDependencies() {
      super.didChangeDependencies();
    
      // 获取亮度值。
      var brightness = MediaQuery.of(context).platformBrightness;
    }
    
  • 使用 WidgetsBindingObserver

    class _MyPageState extends State<MyPage> with WidgetsBindingObserver {
      @override
      void initState() {
        super.initState();
        WidgetsBinding.instance.addObserver(this);
      }
    
      // 每次平台亮度变化时都会调用此回调函数。
      @override
      void didChangePlatformBrightness() {
        super.didChangePlatformBrightness();
    
        // 获取亮度值。
        var brightness = View.of(context).platformDispatcher.platformBrightness;
      }
    
      @override
      void dispose() {
        WidgetsBinding.instance.removeObserver(this);
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) => Container();
    }
    
  • initState 中设置监听器

    @override
    void initState() {
      super.initState();
    
      var dispatcher = SchedulerBinding.instance.platformDispatcher;
    
      // 每次亮度变化时都会调用此回调函数。
      dispatcher.onPlatformBrightnessChanged = () {
        var brightness = dispatcher.platformBrightness;
      };
    }
    

1
运行良好。但是使用此方法将覆盖默认方法。在添加我们的自定义onPlatformBrightnessChanged方法后,主题不会自动更改。如何还能添加一个方法来改变应用程序的主题? - Rehmat Singh Gill
window.onPlatformBrightnessChanged = () { WidgetsBinding.instance.handlePlatformBrightnessChanged(); if (AppStorage.instance.themeMode == ThemeMode.system) { WidgetsBinding.instance.addPostFrameCallback((timeStamp) { setState(() {}); }); } }; - TebessaDev

15

@CopsOnRoad的答案非常完美,但会禁用小部件中对平台亮度更改的自动反应,要解决此问题,请使用以下内容:

@override
void initState() {
  super.initState();

  var window = WidgetsBinding.instance!.window;
  window.onPlatformBrightnessChanged = () {
    WidgetsBinding.instance?.handlePlatformBrightnessChanged();
    // This callback is called every time the brightness changes.
    var brightness = window.platformBrightness;
  };
}

另一种处理方式:

class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver {
  @override
  void initState() {
    WidgetsBinding.instance?.addObserver(this);
    super.initState();
  }

  @override
  void dispose() {
    WidgetsBinding.instance?.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangePlatformBrightness() {
    var brightness = Theme.of(context).brightness;
    super.didChangePlatformBrightness();
  }
}


2

1

有2种亮度类型:

  • MediaQueryData.platformBrightness:"主机平台的当前亮度模式"
  • MediaQueryData.brightness:"整体的主题亮度"。你可能想要这个。

如果您在应用程序中有一个设置,让用户可以独立于操作系统配置不同的亮度,则platformBrightness无效。您需要使用您的应用亮度。

    // Doesn't always work, because platformBrightness is: "The current brightness mode of the host platform".
    final brightness_wrong_1 = MediaQuery.platformBrightnessOf(context);
    final brightness_wrong_2 = MediaQuery.of(context).platformBrightness;
    // If you use flutter hooks (doesn't work)
    final brightness_wrong_3 = usePlatformBrightness();
    // Works:
    final brightness = Theme.of(context).brightness;

0

[2022年2月] - 对我来说工作正常。

使用 - final Brightness brightness = MediaQuery.platformBrightnessOf(context);

这将监听主题更改。您可以根据此更改以不同方式呈现。

 @override
  Widget build(BuildContext context) {
    final Brightness brightness = MediaQuery.platformBrightnessOf(context);
    bool isDarkMode = brightness == Brightness.dark;

稍后小部件将根据isDarkMode进行渲染

例如:

AssetImage(isDarkMode ? darkBgImage : lightBgImage)

Container(
              decoration: BoxDecoration(
                image: DecorationImage(
                  image: AssetImage(isDarkMode ? darkBgImage : lightBgImage),
                  fit: BoxFit.cover,
                  colorFilter:
                      const ColorFilter.mode(Colors.black45, BlendMode.darken),
                ),
              ),
            ),

如果你再读一遍问题,你会发现作者已经尝试过你的答案了。所以请提供另一个解决方案。 - M Karimi
作者是否试图更改AppBar的颜色? - Anand A Nair

0

有一个ThemeMode枚举(我认为自Flutter版本1.9以来)。因此,您可以将theme设置为light,将darkTheme设置为dark,并且themeModeThemeMode.system(默认),ThemeMode.lightThemeMode.dark)确定将使用哪个主题。

MaterialApp(
  theme: ThemeData.light(),
  darkTheme: ThemeData.dark(),
  themeMode: ThemeMode.system,
)

然而,我不确定是否有一种方法可以监听平台亮度的变化(ThemeMode 在幕后也使用了平台亮度)。您需要重新构建 MaterialApp...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接