当前位置: 首页 > 知识库问答 >
问题:

如何在颤振中实现暗模式和亮模式?

赵驰
2023-03-14

我想创建一个flutter应用程序,它有2个明暗模式主题,通过应用程序内的开关进行更改,默认主题是默认的android主题。
我需要将一些自定义颜色传递给其他小部件,我不想只是配置材料主题。

  • 如何检测用户设备默认主题
  • 第二个问题是如何为整个应用程序提供主题
  • 第三个问题是如何通过运行时间的简单切换来改变主题

共有3个答案

鲁德佑
2023-03-14

以下是实现暗模式的三种方法:

  • 始终暗模式

要仅在黑暗模式下运行应用程序,请执行以下操作:

  • 在MaterialApp中,替换主题数据(…) 带有主题数据。dark()

旧的

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData.dark(), // default dark theme replaces default light theme
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}
  • 仅适用于Android 10、iOS 13(引入暗模式时)
  • 为了让设备/平台设置主题,MaterialApp需要3个参数:
    • 主题:主题数据()
    • darkTheme:ThemeData()。深色
    • <代码>主题模式:主题模式。系统
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(),
          darkTheme: ThemeData.dark(), // standard dark theme
          themeMode: ThemeMode.system, // device controls theme
          home: MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    • (您可以使用自定义主题。为了简单起见,以上是默认主题)
    • 我们的应用程序可以在亮模式或暗模式下运行,由用户控制并在应用程序内的运行时自由切换,完全忽略设备的主题设置
    • 和以前一样,将所有三个主题参数提供给MaterialApp主题:暗主题:themeMode:,但我们将调整themeMode:以使用下面的状态字段
    • 要在应用程序中切换亮/暗模式,我们将在ThemeMode.lightThemeMode.dark之间交换themeMode:参数并重建MaterialApp小部件。

    如何重建MaterialApp小部件

    • 要从任何地方切换应用程序主题,我们需要从应用程序中的任何地方访问MaterialApp
    • 我们可以不使用任何包,只使用StatefulWidget,也可以使用状态管理包
    • 使用下面的StatefulWidget在应用程序中任意位置切换运行时主题的示例

    之前-无状态

    • 我们从这个开始,但接下来我们将用StatefulWidget替换它
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(),
          darkTheme: ThemeData.dark(), // standard dark theme
          themeMode: ThemeMode.system, // device controls theme
          home: MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    

    后-状态

    • 在这里,我们用一个StatefulWidget及其补充的State类取代了MyApp
    class MyApp extends StatefulWidget {
      @override
      _MyAppState createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(),
          darkTheme: ThemeData.dark(), // standard dark theme
          themeMode: ThemeMode.system, // device controls theme
          home: MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    

    向StatefulWidget添加静态访问器

    • 将这个静态的of()方法添加到我们的StatefulWidget中,可以使任何子小部件都可以访问它的State对象
    class MyApp extends StatefulWidget {
      @override
      _MyAppState createState() => _MyAppState();
    
      /// ↓↓ ADDED
      /// InheritedWidget style accessor to our State object. 
      static _MyAppState of(BuildContext context) => 
          context.findAncestorStateOfType<_MyAppState>()!;
    }
    
    /// State object hidden ↓. Focusing on ↑ StatefulWidget here.
    
    • 注意我们的()方法的返回类型:\u MyAppState
    • 我们没有得到StatefulWidget,我们得到的是它的State对象:\u MyAppState
    • \u MyAppState将保持我们的模式设置的“状态”(在下一步中)。这就是我们应用程序当前主题的控制因素
    • 接下来,在我们的MyAppState类中,我们将添加一个主题模式字段和一个更改主题的方法

    _MyAppState

    • 下面是我们的状态类修改为:
      1. “状态”字段显示模式
      2. MaterialAppthemode:arg使用themode状态字段值
      3. 更改主题方法
    class _MyAppState extends State<MyApp> {
      /// 1) our themeMode "state" field
      ThemeMode _themeMode = ThemeMode.system;
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(),
          darkTheme: ThemeData.dark(),
          themeMode: _themeMode, // 2) ← ← ← use "state" field here //////////////
          home: MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    
      /// 3) Call this to change theme from any context using "of" accessor
      /// e.g.:
      /// MyApp.of(context).changeTheme(ThemeMode.dark);
      void changeTheme(ThemeMode themeMode) {
        setState(() {
          _themeMode = themeMode;
        });
      }
    }
    
    • 接下来,我们将展示如何访问changeTheme()来更改主题

    更改主题

    • 下面是一个使用()的访问器方法查找我们的状态对象的示例,并从下面的两个按钮调用其changeTheme方法:
    class MyHomePage extends StatelessWidget {
      final String title;
    
      MyHomePage({this.title});
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(title),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  'Choose your theme:',
                ),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    /// //////////////////////////////////////////////////////
                    /// Change theme & rebuild to show it using these buttons 
                    ElevatedButton(
                        onPressed: () => MyApp.of(context).changeTheme(ThemeMode.light),
                        child: Text('Light')),
                    ElevatedButton(
                        onPressed: () => MyApp.of(context).changeTheme(ThemeMode.dark),
                        child: Text('Dark')),
                    /// //////////////////////////////////////////////////////
                  ],
                ),
              ],
            ),
          ),
        );
      }
    }
    
    

    要将主题控制返回到设备的暗模式设置,请创建第三个按钮,该按钮调用将主题模式设置为。系统:

    • MyApp。属于(上下文)。changeTheme(主题模式系统)

    运行此方法将把应用程序主题的控制权委托给设备当前使用的任何暗模式设置。

    代码:本要点中提供完整的复制粘贴代码。

于高雅
2023-03-14

在我看来,最简单的方法是使用提供商来管理应用程序的状态,并使用shared_首选项将主题首选项保存在文件系统中。通过执行此过程,您可以保存主题,这样用户就不必每次都切换主题。

您可以轻松地将主题首选项以字符串的形式存储,然后在应用程序开始时检查文件系统中是否存储了值,如果有,请按如下所示应用该主题。

StorageManager。飞奔

import 'package:shared_preferences/shared_preferences.dart';

class StorageManager {
  static void saveData(String key, dynamic value) async {
    final prefs = await SharedPreferences.getInstance();
    if (value is int) {
      prefs.setInt(key, value);
    } else if (value is String) {
      prefs.setString(key, value);
    } else if (value is bool) {
      prefs.setBool(key, value);
    } else {
      print("Invalid Type");
    }
  }

  static Future<dynamic> readData(String key) async {
    final prefs = await SharedPreferences.getInstance();
    dynamic obj = prefs.get(key);
    return obj;
  }

  static Future<bool> deleteData(String key) async {
    final prefs = await SharedPreferences.getInstance();
    return prefs.remove(key);
  }
}

在如下所示的主题变量中定义主题属性,并根据存储中的值初始化\u主题数据变量。

主题anager.dart

import 'package:flutter/material.dart';
import '../services/storage_manager.dart';

class ThemeNotifier with ChangeNotifier {
  final darkTheme = ThemeData(
    primarySwatch: Colors.grey,
    primaryColor: Colors.black,
    brightness: Brightness.dark,
    backgroundColor: const Color(0xFF212121),
    accentColor: Colors.white,
    accentIconTheme: IconThemeData(color: Colors.black),
    dividerColor: Colors.black12,
  );

  final lightTheme = ThemeData(
    primarySwatch: Colors.grey,
    primaryColor: Colors.white,
    brightness: Brightness.light,
    backgroundColor: const Color(0xFFE5E5E5),
    accentColor: Colors.black,
    accentIconTheme: IconThemeData(color: Colors.white),
    dividerColor: Colors.white54,
  );

  ThemeData _themeData;
  ThemeData getTheme() => _themeData;

  ThemeNotifier() {
    StorageManager.readData('themeMode').then((value) {
      print('value read from storage: ' + value.toString());
      var themeMode = value ?? 'light';
      if (themeMode == 'light') {
        _themeData = lightTheme;
      } else {
        print('setting dark theme');
        _themeData = darkTheme;
      }
      notifyListeners();
    });
  }

  void setDarkMode() async {
    _themeData = darkTheme;
    StorageManager.saveData('themeMode', 'dark');
    notifyListeners();
  }

  void setLightMode() async {
    _themeData = lightTheme;
    StorageManager.saveData('themeMode', 'light');
    notifyListeners();
  }
}

使用themeProvider包装您的应用程序,然后使用消费者应用主题。通过这样做,每当您更改主题的值并调用通知侦听器小部件时,都会重建以同步更改。

主要的飞奔

void main() {
  return runApp(ChangeNotifierProvider<ThemeNotifier>(
    create: (_) => new ThemeNotifier(),
    child: MyApp(),
  ));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<ThemeNotifier>(
      builder: (context, theme, _) => MaterialApp(
        theme: theme.getTheme(),
        home: Scaffold(
          appBar: AppBar(
            title: Text('Hybrid Theme'),
          ),
          body: Row(
            children: [
              Container(
                child: FlatButton(
                  onPressed: () => {
                    print('Set Light Theme'),
                    theme.setLightMode(),
                  },
                  child: Text('Set Light Theme'),
                ),
              ),
              Container(
                child: FlatButton(
                  onPressed: () => {
                    print('Set Dark theme'),
                    theme.setDarkMode(),
                  },
                  child: Text('Set Dark theme'),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

这是github存储库的链接。

柴嘉年
2023-03-14

使用Material App

MaterialApp(
      title: 'App Title',
      theme: ThemeData(
        brightness: Brightness.light,
        /* light theme settings */
      ),
      darkTheme: ThemeData(
        brightness: Brightness.dark,
        /* dark theme settings */
      ),
      themeMode: ThemeMode.dark, 
      /* ThemeMode.system to follow system theme, 
         ThemeMode.light for light theme, 
         ThemeMode.dark for dark theme
      */
      debugShowCheckedModeBanner: false,
      home: YourAppHomepage(),
    );

使用库比蒂诺应用程序

>

  • 使用WidgetsBinding.instance?.window.platformBrightness检测黑暗模式

    您可能还必须监听来自系统的亮度变化,以便使用WidgetsBinding观测器进行实时更新,并覆盖didChangePlatformBriness();

    库比蒂诺App示例:

    class MyApp extends StatefulWidget {
      const MyApp({Key? key}) : super(key: key);
    
      @override
      State<MyApp> createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
      Brightness? _brightness;
    
      @override
      void initState() {
        WidgetsBinding.instance?.addObserver(this);
        _brightness = WidgetsBinding.instance?.window.platformBrightness;
        super.initState();
      }
    
      @override
      void dispose() {
        WidgetsBinding.instance?.removeObserver(this);
        super.dispose();
      }
    
      @override
      void didChangePlatformBrightness() {
        if (mounted) {
          setState(() {
            _brightness = WidgetsBinding.instance?.window.platformBrightness;
          });
        }
    
        super.didChangePlatformBrightness();
      }
    
      CupertinoThemeData get _lightTheme =>
          CupertinoThemeData(brightness: Brightness.light, /* light theme settings */);
    
      CupertinoThemeData get _darkTheme => CupertinoThemeData(
            brightness: Brightness.dark, /* dark theme settings */,
          );
    
      @override
      Widget build(BuildContext context) {
        return CupertinoApp(
          title: 'Demo App',
          theme: _brightness == Brightness.dark ? _darkTheme : _lightTheme,
          home: MyHomePage(title: 'Demo Home Page'),
        );
      }
    }
    

    您可以使用scoped_模型、provider、bloc或get来获得无缝体验。

  •  类似资料:
    • 我想知道如何实现在暗模式和光模式下切换图像。我不想把切换应用程序。只需在iOS或Android中切换设置上的黑暗模式。

    • “解决了”我正在尝试为我的网站制作一个暗/亮模式图标,所以我制作了代码: 它工作正常,但只能在html中呈现,所以我将它改成 现在,由于某种原因,所有元素都定位在右下角,尽管我为图像指定了x和y位置。我怎么解决这个?提前道谢! 编辑:原来我只是哑巴,我不知道html img和svg图像有什么不同。解决了,下面是我的代码:

    • 我正在使用Flutter制作一个关于电影的信息列表。现在我希望左边的封面图片是圆角图片。我做了以下操作,但没有成功。谢谢 如下所示

    • 当我在开发iOS应用程序时,我需要在模拟器中测试它与黑暗模式选项,这样我就可以获得更清晰的应用程序用户界面。但当我去设置,我没有得到黑暗模式作为真实设备显示选项。

    • 嗨,我是Kotlin世界的新手。我喜欢到目前为止所看到的,并开始考虑将我们在应用程序中使用的一些库从Java转换为Kotlin。 第二次更新:问题是如何用Kotlin中的一些参数为一个简单的pojo编写一个构建器设计模式?下面的代码是我的尝试,方法是编写java代码,然后使用eclipse-kotlin-plugin转换为Kotlin。

    • 在 macOS 10.14 Mojave中, Apple 为所有 macOS 电脑引入了一个全新的 系统级黑暗模式。 If your app does have a dark mode, you can make your Electron app follow the system-wide dark mode setting. In macOS 10.15 Catalina, Apple in