Flutter 如何在没有 MediaQuery 的情况下获取亮度?

Jus*_*ion 14 dart flutter bloc ios-darkmode flutter-bloc

我的目标是创建一个应用程序,用户可以在其中选择他喜欢的主题。我使用共享首选项保存用户的选择,以便我可以在下次应用程序启动时加载它。用户可以选择: - 深色模式(独立于操作系统设置) - 浅色模式(独立于操作系统设置) - 系统(根据操作系统设置在深色模式和浅色模式之间进行更改) 在 BLoC 的帮助下,我几乎达到了我想要的。但问题是我需要在 Bloc 事件中传递亮度。为了获得系统(操作系统)亮度,我需要利用

MediaQuery.of(context).platformBrightness
Run Code Online (Sandbox Code Playgroud)

但 Bloc 在 MaterialApp 之前启动,因此 MediaQuery 不可用。当然,我可以稍后传递亮度(从 MaterialApp 的子小部件),但随后(例如,如果用户激活了黑暗模式)它会从亮到暗,但对用户来说可见的时间很短(因为在 InitialState 内)我在灯光模式下通过了)。

class MyApp extends StatelessWidget {
  final RecipeRepository recipeRepository;

  MyApp({Key key, @required this.recipeRepository})
      : assert(recipeRepository != null),
        super(key: key);

  @override
  Widget build(BuildContext context) {
    return MultiBlocProvider(
      providers: [
        BlocProvider<ThemeBloc>(create: (context) =>
        ThemeBloc(),),

      ],
      child: BlocBuilder<ThemeBloc, ThemeState>(
        builder: (context, state){

          return MaterialApp(
            theme: state.themeData,
            title: 'Flutter Weather',
            localizationsDelegates: [
              FlutterI18nDelegate(fallbackFile: 'en',),
              GlobalMaterialLocalizations.delegate,
              GlobalWidgetsLocalizations.delegate
            ],
            supportedLocales: [
              const Locale("en"),
              const Locale("de"),
            ],
            home: Home(recipeRepository: recipeRepository),
          );
        },
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

主题块:

class ThemeBloc extends Bloc<ThemeEvent, ThemeState> {
  @override
  ThemeState get initialState =>
      ThemeState(themeData: appThemeData[AppTheme.Bright]);

  @override
  Stream<ThemeState> mapEventToState(
    ThemeEvent event,
  ) async* {
    if (event is LoadLastTheme) {
      ThemeData themeData = await _loadLastTheme(event.brightness);
      yield ThemeState(themeData: themeData);
    }
    if (event is ThemeChanged) {
      await _saveAppTheme(event.theme);
      yield ThemeState(themeData: appThemeData[event.theme]);
    }
  }

  Future<ThemeData> _loadLastTheme(Brightness brightness) async {
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    String themeString = prefs.getString(SharedPrefKeys.appThemeKey);
    print("saved theme: $themeString");
    if ((prefs.getString(SharedPrefKeys.appThemeKey) != null) &&
        themeString != "AppTheme.System") {
      switch (themeString) {
        case "AppTheme.Bright":
          {
            return appThemeData[AppTheme.Bright];
          }
          break;

        ///Selected dark mode
        case "AppTheme.Dark":
          {
            return appThemeData[AppTheme.Dark];
          }
          break;
      }
    }

    print("brightness: $brightness");
    if (brightness == Brightness.dark) {
      return appThemeData[AppTheme.Dark];
    } else {
      return appThemeData[AppTheme.Bright];
    }

  }

  Future<void> _saveAppTheme(AppTheme appTheme) async {
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setString(SharedPrefKeys.appThemeKey, appTheme.toString());
  }
}
Run Code Online (Sandbox Code Playgroud)

Abi*_*n47 12

如果您绝对必须这样做,您可以MediaQuery直接从低级窗口对象获取数据,如下所示:

final brightness = MediaQueryData.fromWindow(WidgetsBinding.instance.window).platformBrightness;
Run Code Online (Sandbox Code Playgroud)

但是,我强烈建议您考虑,如果您需要MediaQuery从您的块内进行访问,您应该将您移至BlocProvider您之后实例化MaterialApp,以便您可以MediaQuery正常访问。


has*_*m08 10

从 Flutter version 开始3.10,使用以下代码:

var brightness = WidgetsBinding.instance.platformDispatcher.platformBrightness;
Run Code Online (Sandbox Code Playgroud)


Ben*_*rth 5

从 flutter 3.7 升级后,现在有 2 个选项:

final mode = PlatformDispatcher.instance.platformBrightness;

// With context
final mode = View.of(context).platformDispatcher.platformBrightness;
Run Code Online (Sandbox Code Playgroud)

较旧的、已弃用的选项

final mode = SchedulerBinding.instance.window.platformBrightness;
Run Code Online (Sandbox Code Playgroud)

错误: 信息:'window' 已弃用,不应使用。通过 View.of(context) 从上下文中查找当前的 FlutterView 或直接查询 PlatformDispatcher。已弃用,为即将到来的多窗口支持做准备。此功能在 v3.7.0-32.0.pre 之后已弃用。([appname] lib/src/settings/settings.dart:88 处的 deprecated_member_use)