下拉按钮状态管理 - Flutter

Dropdownbutton Statemanagement - Flutter

我想在 flutter 中创建一个带有多个下拉按钮的评估应用程序。下拉按钮应包含带有值的文本,例如:dropdownbutton1: "Text"; Value(2), dropdownbutton2: "文本"; Value2(4) 还有另一个按钮“评估”,如果我点击“评估”按钮,它应该转到下一个屏幕,下一个屏幕显示总值(它应该是 6= value(2 ) + 值 2(4).

我的下一个想法是状态管理,但我现在不知道该怎么做。 我在互联网上到处搜索,但找不到任何东西。

我是 Flutter 新手。有没有办法通过状态管理来实现它,它看起来会是什么样子?

您绝对应该实施一种状态管理,既用于页面之间的通信,也用于向下拉菜单提供数据,并保留下拉菜单中的选定值。

我的建议是使用像 Provider 状态管理策略这样简单的东西,并利用有助于侦听应用程序发生的变化的小部件。此策略使您的应用程序更加解耦,保持关注点的清晰分离并允许良好的维护。

您可以创建一个 Provided 服务(即 DropdownService),它将下拉菜单的值保存为下拉选项列表,以及两个保存到从下拉列表中选择的值(即 selectedFirstOption、selectedSecondOption)。在两个 DropDownButton 小部件上触发更改后,您可以触发小部件的通知以重建自身、更新其选择并保留所选值。

一个按钮将触发评估并导航到下一页,只有当 selectedFirstOptionselectedSecondOption 都不为 null 时,则下一页还使用提供的 DropdownService,提取为两个选择保留的数据,添加值并将其显示给用户。

我把一些东西放在一起作为例子来说明我的观点:


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

const Color darkBlue = Color.fromARGB(255, 18, 32, 47);

void main() {
  
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(
          create: (_) => DropdownService()
        )
      ],
      child: MyApp()
    )
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark().copyWith(
        scaffoldBackgroundColor: darkBlue,
      ),
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: MyWidget(),
        ),
      ),
    );
  }
}

class MyWidget extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    
    return Consumer<DropdownService>(
      builder: (context, dropdownService, child) {
        return Container(
            padding: const EdgeInsets.all(30),
            child: Column(
              children: [
                const Text('First dropdown:'),
                DropdownButton<DropdownOption>(
                  value: dropdownService.selectedFirstOption,
                  icon: const Icon(Icons.arrow_drop_down),
                  elevation: 16,
                  onChanged: (DropdownOption? newValue) {
                      dropdownService.selectedFirstOption = newValue!;
                  },
                  items: dropdownService.firstDropdown.map((DropdownOption option) {
                    return DropdownMenuItem<DropdownOption>(
                      value: option,
                      child: Text(option.text!),
                    );
                  }).toList(),
                ),
                const SizedBox(height: 20),
                const Text('Second dropdown:'),
                DropdownButton<DropdownOption>(
                  value: dropdownService.selectedSecondOption,
                  icon: const Icon(Icons.arrow_drop_down),
                  elevation: 16,
                  onChanged: (DropdownOption? newValue) {
                      dropdownService.selectedSecondOption = newValue!;
                  },
                  items: dropdownService.secondDropdown.map((DropdownOption option) {
                    return DropdownMenuItem<DropdownOption>(
                      value: option,
                      child: Text(option.text!),
                    );
                  }).toList(),
                ),
                const SizedBox(height: 20),
                Material(
                  color: Colors.amber,
                  child: TextButton(
                    onPressed: dropdownService.selectedFirstOption != null 
                      && dropdownService.selectedSecondOption != null ? () {
                      
                      Navigator.of(context).push(
                        MaterialPageRoute(builder: (context) => NextPage())
                      );
                    } : null,
                    child: const Text('Evaluate', style: TextStyle(color: Colors.black)
                    )
                  )
                )
              ]
            )
          );
      }
    );
  }
}

class NextPage extends StatelessWidget {

  @override
  Widget build(BuildContext context) {

    DropdownService dropdownService = Provider.of<DropdownService>(context, listen: false);

    return Scaffold(
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Text('The result of ${dropdownService.selectedFirstOption!.text!} and ${dropdownService.selectedSecondOption!.text!}:'),
            const SizedBox(height: 20),
            Text('${dropdownService.selectedFirstOption!.value! + dropdownService.selectedSecondOption!.value!}',
              style: const TextStyle(fontSize: 50)
            ),
          ],
        ),
      ),
    );
  }
}

class DropdownService extends ChangeNotifier {
  
  List<DropdownOption> firstDropdown = [
    DropdownOption(text: 'Value (5)', value: 5),
    DropdownOption(text: 'Value (6)', value: 6),
    DropdownOption(text: 'Value (7)', value: 7),
  ];
  
  DropdownOption? _selectedFirstOption; // = DropdownOption(text: 'Select Value', value: -1);
  DropdownOption? _selectedSecondOption; // = DropdownOption(text: 'Select Value', value: -1);

  DropdownOption? get selectedFirstOption => _selectedFirstOption;
  DropdownOption? get selectedSecondOption => _selectedSecondOption;

  set selectedFirstOption(DropdownOption? value) {
    _selectedFirstOption = value;
    notifyListeners();
  }

  set selectedSecondOption(DropdownOption? value) {
    _selectedSecondOption = value;
    notifyListeners();
  } 
  
  List<DropdownOption> secondDropdown = [
    DropdownOption(text: 'Value (1)', value: 1),
    DropdownOption(text: 'Value (2)', value: 2),
    DropdownOption(text: 'Value (3)', value: 3),
  ];
}


class DropdownOption {
  String? text;
  double? value;
  
  DropdownOption({ this.text, this.value });
}

如果您 运行 通过 DartPad.dev 此代码(也作为 Gist 提供),您应该看到以下输出: