动态更改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
}
答案 0 :(得分:2)
如果愿意,您可以使用InhertedWidget(而不是BLOC)-基本上,它用于访问树上任何位置的父窗口小部件。
所以你应该做的
InheritedWidget
[您希望从中发生主题效果的地方] Theme
小部件上以下是一些代码:
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);