Flutter:如何使用带有提供程序的DropDownButton?

时间:2020-04-26 13:29:29

标签: flutter

我有一个dropDownButton,可在其中选择整个应用程序的主题。我尝试了两种实际尝试解决此问题的方法。第一个是使用注释行“ Provider.of(context).toggleTheme();”。在“ setState”中。必须按照另一个线程中的建议将“侦听”选项设置为“假”,但是它不起作用。第二个是只在“ Themes.dart”中调用“ toggleTheme()”,以便以这种方式通知侦听器。像这样的Dropdownbutton会是正确的实现。

MainScreen.dart

import 'package:flutter/material.dart';
import 'package:thisismylastattempt/Misc/Themes.dart';
import 'package:provider/provider.dart';


class MainScreen extends StatefulWidget {
  static const id = "main_screen";

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


class ThemeOptions{
  final Color themeColor;
  final ThemeType enumTheme;
  ThemeOptions({this.themeColor, this.enumTheme});

  void callParentTheme(){
    ThemeModel().changeEnumValue(enumTheme);
  }
}


class _MainScreenState extends State<MainScreen> {


  List<ThemeOptions> themes = [
    ThemeOptions(themeColor: Colors.teal, enumTheme: ThemeType.Teal),
    ThemeOptions(themeColor: Colors.green, enumTheme: ThemeType.Green),
    ThemeOptions(themeColor: Colors.lightGreen, enumTheme: ThemeType.LightGreen),
  ];

  ThemeOptions dropdownValue;

  @override
  void initState() {
     dropdownValue = themes[0];
    super.initState();
  }
  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(
        title: Text('MainScreen'),
      ),
      body: Column(
       children: <Widget>[
         Container(
           child: DropdownButton<ThemeOptions>(
             value: dropdownValue,
             icon: Icon(Icons.arrow_downward),
             iconSize: 24,
             elevation: 16,
             style: TextStyle(
                 color: Colors.deepPurple
             ),
             underline: Container(
               height: 0.0,
               color: Colors.deepPurpleAccent,
             ),
             onChanged: (ThemeOptions newValue) {
               setState(() {
                 dropdownValue = newValue;
                 dropdownValue.callParentTheme();
                 print(newValue.themeColor);
                 //Provider.of<ThemeModel>(context).toggleTheme();
               });
             },
             items: themes.map((ThemeOptions colorThemeInstance) {
               return DropdownMenuItem<ThemeOptions>(
                 value: colorThemeInstance,
                 child: CircleAvatar(
                   backgroundColor: colorThemeInstance.themeColor,
                 ),
               );
             })
                 .toList(),
           ),
         ),
         SizedBox(height: 20.0,),
       ],
      ),
    );
  }
}

Themes.dart

import 'package:flutter/material.dart';

enum ThemeType {Teal, Green, LightGreen}

ThemeData tealTheme = ThemeData.light().copyWith(

  primaryColor: Colors.teal.shade700,
  appBarTheme: AppBarTheme(
    color: Colors.teal.shade700,
  ),

);

ThemeData greenTheme = ThemeData.light().copyWith(

  primaryColor: Colors.green.shade700,
  appBarTheme: AppBarTheme(
    color: Colors.green.shade700,
  ),

);

ThemeData lightGreenTheme = ThemeData.light().copyWith(

  primaryColor: Colors.lightGreen.shade700,
  appBarTheme: AppBarTheme(
    color: Colors.lightGreen.shade700,
  ),

);

class ThemeModel extends ChangeNotifier {
  ThemeData currentTheme = tealTheme;
  ThemeType _themeType = ThemeType.Teal;

  toggleTheme() {
    if (_themeType == ThemeType.Teal) {
      currentTheme = tealTheme;
      _themeType = ThemeType.Teal;
      print('teal');
       notifyListeners();
    }

    if (_themeType == ThemeType.Green) {
      currentTheme = greenTheme;
      _themeType = ThemeType.Green;
      print('green');
       notifyListeners();
    }
    if (_themeType == ThemeType.LightGreen) {
      currentTheme = lightGreenTheme;
      _themeType = ThemeType.LightGreen;
      print('lightGreen');
       notifyListeners();
    }
  }

  ThemeType getEnumValue(){
    return _themeType;
  }

  void changeEnumValue(ThemeType newThemeType){
   _themeType = newThemeType;
   toggleTheme();
  }

}

main.dart

void main() => runApp(ChangeNotifierProvider<ThemeModel>(
    create: (BuildContext context) => ThemeModel(), child: MyApp()));

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return StreamProvider<User>.value(
      value: AuthService().user,
      child: MaterialApp(
        theme: Provider.of<ThemeModel>(context).currentTheme,
        title: 'Flutter Demo',
        initialRoute: MainScreen.id,
        routes: {
          Wrapper.id: (context) => Wrapper(),
          LoginPage.id: (context) => LoginPage(),
          Registration.id: (context) => Registration(),
          MainScreen.id: (context) => MainScreen(),
          SwitchAuthenticationState.id: (context) =>
              SwitchAuthenticationState(),
        },
      ),
    );
  }
}

1 个答案:

答案 0 :(得分:0)

我设法通过在您的constexpr类的changeEnumValue中的Provider中调用callParentTheme来使其工作:

ThemeOptions

在您的class ThemeOptions { final Color themeColor; final ThemeType enumTheme; ThemeOptions({this.themeColor, this.enumTheme}); // void callParentTheme() { // ThemeModel().changeEnumValue(enumTheme); void callParentTheme(context) { Provider.of<ThemeModel>(context, listen: false).changeEnumValue(enumTheme); } DropDown方法中调用带有上下文的方法:

onChanged

希望有帮助