【问题标题】:How to add a switch to change Flutter App theme?如何添加开关来更改 Flutter App 主题?
【发布时间】:2020-11-26 17:41:11
【问题描述】:

我是新手,在尝试在 Appbar 上合并一个更改整个应用主题的按钮时遇到问题。

这是 ma​​in.dart 文件代码。

import 'package:flutter/material.dart';
import 'package:qrpay_app/routes/Routes.dart';
import 'module/splash/splash_view.dart';
import 'module/buy/buy_list_view.dart';
import 'module/sell/sell_list_view.dart';
import 'module/shop/shop_list_view.dart';
import 'module/account/account_list_view.dart';
import 'module/contact/contact_list_view.dart';
import 'module/help/help_list_view.dart';
import 'module/receipts/receipts_list_view.dart';
import 'module/about us/about_us_view.dart';
import 'package:qrpay_app/Themes/appThemes.dart';

import 'module/qr/qr_view.dart';

void main() {
  runApp(new MaterialApp(
    title: 'QRPAY Touch-Free',
    theme: new ThemeData(primarySwatch: Colors.red),
    home: SplashPage(),
    routes: {
      Routes.splash: (context) => SplashPage(),
      Routes.buy: (context) => BuyPage(),
      Routes.sell: (context) => SellPage(),
      Routes.shop: (context) => ShopPage(),
      Routes.qr: (context) => QRPage(),
      Routes.account: (context) => AccountPage(),
      Routes.contact: (context) => ContactPage(),
      Routes.help: (context) => HelpPage(),
      Routes.receipts: (context) => ReceiptsPage(),
      Routes.about_us: (context) => AboutUsPage(),
    },
  ));
}

这是 appThemes.dart 代码:

import 'package:flutter/material.dart';

class AppThemes {
  // Simple constructor
  AppThemes._();

  static final ThemeData highContrast = ThemeData(
    primarySwatch: Colors.black,
    primaryTextTheme: TextTheme(
      headline6: TextStyle(color: Colors.white),
    ),
    scaffoldBackgroundColor: Colors.white,
    appBarTheme: AppBarTheme(
      color: Colors.black,
      iconTheme: IconThemeData(
        color: Colors.white,
      ),
      elevation: 30.0,
    ),
  );

  static final ThemeData normalContrast = ThemeData(
    scaffoldBackgroundColor: Colors.white,
    appBarTheme: AppBarTheme(
      color: Colors.red,
      iconTheme: IconThemeData(
        color: Colors.white,
      ),
    ),
  );
}

我已将主页路由到 splash_view.dart。这是 appThemes.dart 代码:

import 'package:flutter/material.dart';
import 'package:qrpay_app/widget/drawer.dart';
import 'package:qrpay_app/Themes/appThemes.dart';

class SplashPage extends StatefulWidget {
  static const String routeName = '/splash';
  @override
  _SplashPageState createState() => _SplashPageState();
}

class _SplashPageState extends State<SplashPage> {
  void changeContrast() {
    print("High contrast button clicked\nChanging app contrast\n");
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("QRPAY Touch-Free"),
        elevation: 30.0,
        actions: <Widget>[
          ElevatedButton(
              onPressed: () {
                changeContrast();
              },
              child: Text('High Contrast')),
        ],
      ),
      drawer: AppDrawer(),
      body: new Center(
        child: new Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            new Container(
              child: new Image.asset(
                'res/images/qplogo.png',
                width: MediaQuery.of(context).size.width * .9,
                fit: BoxFit.cover,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

我添加了一个高架按钮,它需要更改整个应用的主题。请帮助根据我的 dart 文件映射功能。

另外,我对如何添加状态变化感到困惑

我尝试使用“提供者”进行锻炼,但我感到困惑。

请有人帮帮我。另外,如果您需要其他任何内容来更好地理解我的问题,请告诉我。

感谢大家抽出时间帮助我。

谢谢。

【问题讨论】:

  • 尝试放代码而不是图片

标签: flutter dart visual-studio-code flutter-state


【解决方案1】:

您可以在此处阅读有关 Flutter Stream 的文章:https://medium.com/@ayushpguptaapg/using-streams-in-flutter-62fed41662e4

添加一个布尔值来跟踪当前主题

bool isHighContrast = false;

然后当你的开关打开时,只需调用:

// switch is on, toggle isHighContrast. isHighContrast now equals to true
controller.add(isHighContrast);

然后监听更改以更新整个 UI:

controller.stream.listen({
  setState({
    theme = AppTheme.highContrast;
  });
})

【讨论】:

  • 如何实现?我要对每个 dart 文件或在家里路由的文件进行更改吗?此外,此更改将如何反映在应用的所有页面上?
  • 你只需要在你的 MaterialApp 的主题属性中实现它,确保将你的主题放入一个变量中,所以当对比度改变时,你只需调用 setState 并且你的 MaterialApp 中的每个屏幕都会改变
  • 我已经更改了问题请查看它,我还需要根据当前状态更改主题的按钮,如果它处于正常模式则切换到高对比度,如果它处于高对比度模式然后切换到正常模式。
【解决方案2】:

最简单的方法是使用Provider。

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(
    MultiProvider(
      providers: [
      // Used MultiProvider incase you have other providers
        ChangeNotifierProvider<ThemeDataProvider>(
          create: (_) => ThemeDataProvider(),
        ),
      ],
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    ThemeDataProvider themeDataProvider = Provider.of(context);

    // Pull the theme data from the provider and make a few modification
    // The modifications are for illustration only.  Not required.
    final ThemeData currentTheme = themeDataProvider.themeData.copyWith(
      scaffoldBackgroundColor: themeDataProvider.isDarkTheme ? Colors.yellow[700] : Colors.yellow[300],
      appBarTheme: themeDataProvider.themeData.appBarTheme,
      cardTheme: themeDataProvider.themeData.cardTheme,
    );
    return MaterialApp(
      color: Colors.yellow[100],
      title: 'MyApp',
      theme: currentTheme, //set your theme
      initialRoute: setupRoute,
      onGenerateRoute: Router.generateRoute,
    );
  }
}


class ThemeDataProvider with ChangeNotifier {
  Future<SharedPreferences> _prefs = SharedPreferences.getInstance();

  SharedPreferences prefs;
  bool isInitialized;
  bool _useDarkTheme;
  double _appMargin;
  int _animationDuration = 200;
  ThemeData _themeData;

  ThemeDataProvider() {
    isInitialized = false;
    _initialize();
  }

  void _initialize() async {
    prefs = await _prefs;
    await _loadPrefs();
    _themeData = _buildThemeData();
    _appMargin = 0.0;
    isInitialized = true;
  }

  ThemeData get themeData => _themeData;

  bool get isDarkTheme => _useDarkTheme ?? true;
  double get appMargin => _appMargin;
  int get animDuration => _animationDuration;

  ///
  /// Set the application working margin.
  ///
  void setAppMargin(double appMargin) {
    _appMargin = appMargin;
  }

  void toggleTheme() {
    _useDarkTheme = !_useDarkTheme;
    _savePrefs();
    _themeData = _buildThemeData();
    notifyListeners();
  }

  Future _loadPrefs() async {
    prefs = await _prefs;
    _useDarkTheme = prefs.getBool("useDarkMode") ?? true;
    _themeData = _buildThemeData();
    notifyListeners();
  }

  void _savePrefs() async {
    prefs = await _prefs;
    prefs.setBool("useDarkMode", _useDarkTheme);
  }

// Build your theme data here
      ThemeData _buildThemeData() {
        return ThemeData(
          primarySwatch: isDarkTheme
              ? MaterialColor(4280361249, {
                  50: Color(0xfff2f2f2),
    ...

在任何你喜欢的地方添加开关,然后点击调用 toggleTheme 方法。

这不是功能代码。这是我的生产代码的编辑版本。

【讨论】:

  • 我认为这对于一个简单的任务来说太长了,或者我不知道。我是 Flutter 的新手,但我真的希望 Flutter 有一行代码可以改变主题。
【解决方案3】:

我使用 flutter_riverpod 包中的 StateProvider 来实现这一点。

// Add the global provider
final appThemeProvider = StateProvider<ThemeData>((ref) {
  return App.getDefaultThemeData();
});

class App extends ConsumerWidget {
//                ^^^^^^^^^^^^^^
  @override
  Widget build(BuildContext context, WidgetRef ref) {
//                                   ^^^^^^^^^^^^^
    final currentTheme = ref.watch(appThemeProvider).state;

    return MaterialApp(
      color: Colors.yellow[100],
      title: 'MyApp',
      theme: currentTheme, //set your theme
      initialRoute: setupRoute,
      onGenerateRoute: Router.generateRoute,
    );

    // this is default theme
    static ThemeData getDefaultThemeData() {
      return ThemeData(
        primarySwatch: MaterialColor(0xFF00FF00, mappingColor),
        backgroundColor: MaterialColor(0xFFFFFEFA, mappingColor),
      );
    }

    // use this method to changeTheme
    void _changeTheme({required WidgetRef ref, required ThemeData themeData}) {
      Future.delayed(const Duration(milliseconds: 10), () {
        ref.read(appThemeProvider).state = themeData;
      }
    }
} 

【讨论】:

    猜你喜欢
    • 2021-08-19
    • 1970-01-01
    • 2013-05-10
    • 2020-11-02
    • 1970-01-01
    • 2021-11-08
    • 1970-01-01
    • 1970-01-01
    • 2017-06-21
    相关资源
    最近更新 更多