【问题标题】:how to change app theme in runtime in Flutter?如何在 Flutter 运行时更改应用程序主题?
【发布时间】:2018-11-19 17:26:13
【问题描述】:

在我的简单项目中,有一个按钮可以将主题从浅色变为深色,反之亦然,如下所示:

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:async';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  MyAppState createState() {
    return new MyAppState();
  }
}

class MyAppState extends State<MyApp> {
  Future<bool> load(String key, bool defaultValue) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    bool state = prefs.getBool(key) ?? defaultValue;
    return state;
  }

  Future<void> save(String key, bool value) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    prefs.setBool(key, value);
  }

  bool state;

  @override
  Widget build(BuildContext context) {
    load("themeKey", false).then((bool value) {
      state = value;
    });
    debugPrint(
        "..............state is : " + state.toString() + "...............");
    return MaterialApp(
      theme: state ? ThemeData.light() : ThemeData.dark(),
      home: Scaffold(
        body: Container(
          child: RaisedButton(
            child: Text("change"),
            onPressed: () {
              setState(() {
                state = !state;
              });
              save("themeKey", state);
            },
          ),
        ),
      ),
    );
  }
}

我使用shared_preferences 插件来保存当前主题状态以供下一次应用启动,但似乎存在一个问题,即应用在共享首选项加载之前加载,所以我得到了这个异常

Launching lib\main.dart on C1905 in debug mode...
Built build\app\outputs\apk\debug\app-debug.apk.
I/flutter ( 8045): ..............state is : null...............
I/flutter ( 8045): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter ( 8045): The following assertion was thrown building MyApp(dirty, state: MyAppState#6774f):
I/flutter ( 8045): Failed assertion: boolean expression must not be null
I/flutter ( 8045): Either the assertion indicates an error in the framework itself, or we should provide substantially
I/flutter ( 8045): more information in this error message to help you determine and fix the underlying cause.
I/flutter ( 8045): In either case, please report this assertion by filing a bug on GitHub:
I/flutter ( 8045):   https://github.com/flutter/flutter/issues/new?template=BUG.md
I/flutter ( 8045): When the exception was thrown, this was the stack:
I/flutter ( 8045): #0      MyAppState.build (package:test_shared_preferenced/main.dart:36:14)
I/flutter ( 8045): #1      StatefulElement.build (package:flutter/src/widgets/framework.dart:3787:27)
I/flutter ( 8045): #2      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3699:15)
I/flutter ( 8045): #3      Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
I/flutter ( 8045): #4      ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3679:5)
I/flutter ( 8045): #5      StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:3826:11)
I/flutter ( 8045): #6      ComponentElement.mount (package:flutter/src/widgets/framework.dart:3674:5)
I/flutter ( 8045): #7      Element.inflateWidget (package:flutter/src/widgets/framework.dart:2950:14)
I/flutter ( 8045): #8      Element.updateChild (package:flutter/src/widgets/framework.dart:2753:12)
I/flutter ( 8045): #9      RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:909:16)
I/flutter ( 8045): #10     RenderObjectToWidgetElement.mount (package:flutter/src/widgets/binding.dart:880:5)
I/flutter ( 8045): #11     RenderObjectToWidgetAdapter.attachToRenderTree.<anonymous closure> (package:flutter/src/widgets/binding.dart:826:17)
I/flutter ( 8045): #12     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2266:19)
I/flutter ( 8045): #13     RenderObjectToWidgetAdapter.attachToRenderTree (package:flutter/src/widgets/binding.dart:825:13)
I/flutter ( 8045): #14     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding&WidgetsBinding.attachRootWidget (package:flutter/src/widgets/binding.dart:712:7)
I/flutter ( 8045): #15     runApp (package:flutter/src/widgets/binding.dart:756:7)
I/flutter ( 8045): #16     main (package:test_shared_preferenced/main.dart:5:16)
I/flutter ( 8045): #17     _startIsolate.<anonymous closure> (dart:isolate/runtime/libisolate_patch.dart:289:19)
I/flutter ( 8045): #18     _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:171:12)
I/flutter ( 8045): ════════════════════════════════════════════════════════════════════════════════════════════════════

遇到这种情况我该怎么办,请帮忙

【问题讨论】:

  • 状态返回null,将条件改为:Dart return MaterialApp( theme: state == null ? ThemeData.light() : ThemeData.dark(), ...)
  • @EdgarHuamani 您试图建议的内容将防止空值错误,但未正确考虑用户的主题偏好。在执行此代码之前,绝大多数时间状态都不会被设置。这意味着无论用户偏好如何设置,它将默认为浅色主题。一旦加载未来完成并且主题偏好已知,最好设置主题。
  • 我想让执行等待加载方法完成,请问我该如何实现
  • @Stephen 我只回答了如何解决日志显示的错误。你是对的,ThemeData.light () 会一直被选中,@Hasan 你可以选择使用FutureBuilder 我想你在下面已经有回复了。

标签: dart flutter


【解决方案1】:

load 方法返回一个Future,它将与您的其余代码异步运行。当执行到达debugPrint 或随后的return 语句时,您不能保证then 块已完成执行。您收到的错误证实了这一点。 state 布尔值尚未设置为值 - 它仍然为空。

使用FutureBuilder 可以帮助您处理等待Future 构建小部件树的情况。

https://www.dartlang.org/tutorials/language/futures 值得一读。

【讨论】:

  • 它与 FutureBuilder 完美配合,非常感谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-01-17
  • 2020-11-02
  • 1970-01-01
  • 2022-11-11
  • 1970-01-01
  • 1970-01-01
  • 2020-02-04
相关资源
最近更新 更多