颤振动态主题

时间:2019-02-19 01:01:52

标签: dart flutter

动态更改Flutter应用程序主题的最佳方法是什么?例如,如果用户将颜色更改为红色,我希望将主题立即更改为红色。除了一个人说我使用BLOC模式,我对此并不熟悉,我在网上找不到任何有用的东西。我想听听你们对这个问题的想法。谢谢!

我当前的代码结构:

var themeData = ThemeData(
    fontFamily: 'Raleway',
    primaryColor: Colors.blue,
    brightness: Brightness.light,
    backgroundColor: Colors.white,
    accentColor: Colors.blue);

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: Constants.appName,
      theme: themeData,
      home: CheckAuth(), //CheckAuth returns MyHomePage usually
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title, @required this.uid}) : super(key: key);

  final String title;
  final String uid;

  @override
  _MyHomePageState createState() => _MyHomePageState();
    }

class _MyHomePageState extends State<MyHomePage> {
    ...build and stuff
    }

3 个答案:

答案 0 :(得分:2)

如果愿意,您可以使用InhertedWidget(而不是BLOC)-基本上,它用于访问树上任何位置的父窗口小部件。

所以你应该做的

  1. 在树顶上的某个位置创建InheritedWidget [您希望从中发生主题效果的地方]
  2. 将其包装在Theme小部件上
  3. 通过传递您要替换为主题的ThemeData,公开一种切换主题的方法。

以下是一些代码:

import 'package:flutter/material.dart';

var themeData = ThemeData(
    fontFamily: 'Raleway',
    primaryColor: Colors.blue,
    brightness: Brightness.light,
    backgroundColor: Colors.white,
    accentColor: Colors.blue
);

void main() {
  runApp(
    ThemeSwitcherWidget(
      initialTheme: themeData,
      child: MyApp(),
    ),
  );
}

class ThemeSwitcher extends InheritedWidget {
  final _ThemeSwitcherWidgetState data;

  const ThemeSwitcher({
    Key key,
    @required this.data,
    @required Widget child,
  })  : assert(child != null),
        super(key: key, child: child);

  static _ThemeSwitcherWidgetState of(BuildContext context) {
    return (context.inheritFromWidgetOfExactType(ThemeSwitcher)
            as ThemeSwitcher)
        .data;
  }

  @override
  bool updateShouldNotify(ThemeSwitcher old) {
    return this != old;
  }
}

class ThemeSwitcherWidget extends StatefulWidget {
  final ThemeData initialTheme;
  final Widget child;

  ThemeSwitcherWidget({Key key, this.initialTheme, this.child})
      : assert(initialTheme != null),
        assert(child != null),
        super(key: key);

  @override
  _ThemeSwitcherWidgetState createState() => _ThemeSwitcherWidgetState();
}

class _ThemeSwitcherWidgetState extends State<ThemeSwitcherWidget> {
  ThemeData themeData;

  void switchTheme(ThemeData theme) {
    setState(() {
      themeData = theme;
    });
  }

  @override
  Widget build(BuildContext context) {
    themeData = themeData ?? widget.initialTheme;
    return ThemeSwitcher(
      data: this,
      child: widget.child,
    );
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeSwitcher.of(context).themeData,
      home: CheckAuth(),
    );
  }
}

我将ThemeSwitcherWidget包裹在MaterialApp周围,因此效果遍及整个应用程序(即使当您使用Navigator推送新路线时也是如此)。

在ThemeSwithcerWidget下面的任意位置使用ThemeSwitcher.of(context).switchTheme(themeData)更改主题。

在有问题的情况下,应调用ThemeSwitcher.of(context).switchTheme(Theme.of(context).copyWith(primaryColor: Colors.red))将整个应用程序中的原色切换为红色,例如。在某些按钮上单击

答案 1 :(得分:1)

使用provider软件包:
theme_changer.dart

var darkTheme = ThemeData.dark();
var lightTheme= ThemeData.light();

class ThemeChanger extends ChangeNotifier {
  ThemeData _themeData;
  ThemeChanger(this._themeData);

  get getTheme => _themeData;
  void setTheme(ThemeData theme) {
    _themeData = theme;
    notifyListeners();
  }
}

main.dart

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => ThemeChanger(lightTheme)),
      ],
      child: MaterialAppWithTheme(),
    );
  }
}

class MaterialAppWithTheme extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final theme = Provider.of<ThemeChanger>(context);
    return MaterialApp(
      theme: theme.getTheme,
      home: FirstScreen(),
    );
  }

first_screen.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import './theme_changer.dart'

class FirstScreen extends StatelessWidget{
  @override
  Widget build(BuildContext context){
    var _themeProvider=Provider.of<ThemeChanger>(context);
    return Scaffold(
      appBar: AppBar(title:Text("First Screen"),),
      body:Container(width:MediaQuery.of(context).size.width,
           height:MediaQuery.of(context).size.height,
           child:Center(
                child:FlatButton(child:Text("Press me"). onPressed:(){
                  _themeProvider.setTheme(_themeProvider.getTheme==lightTheme?darkTheme:lightTheme);
                })
           ),
      ),
    );
  }
}

答案 2 :(得分:0)

这是在您的应用程序中实现动态主题更改的方法:

1。您应该将MyApp更改为Stateful小部件,以使类在颜色更改时能够重新构建:

 var _primary = Colors.blue ; // This will hold the value of the app main color

 var themeData = ThemeData(
 fontFamily: 'Raleway',
 primaryColor: _primary, // so when the rebuilds the color changes take effect
 brightness: Brightness.light,
 backgroundColor: Colors.white,
 accentColor: Colors.blue);

 void main() => runApp(new App());

 class App extends StatefulWidget {
 App({Key key,}) :

 super(key: key);

  @override
  _AppState createState() => new _AppState();

  static void setTheme(BuildContext context, Color newColor) {
  _AppState state = context.ancestorStateOfType(TypeMatcher<_AppState>());
   state.setState(() {
     state._primary = newColor;
    });
  }
}

2。静态方法setTheme将是负责颜色更改的方法:

  class _AppState extends State<App> {

  @override
  Widget build(BuildContext context) {
  return MaterialApp(
  title: Constants.appName,
  theme: themeData,
  home: CheckAuth(), //CheckAuth returns MyHomePage usually
  );
 }
}   

3。要从代码的任何位置更改主题颜色时,请调用此方法:

  App.setTheme(context, Colors.blue);