【问题标题】:Flutter pass data between widgets?Flutter 在小部件之间传递数据?
【发布时间】:2019-04-22 19:02:42
【问题描述】:

我有两个有状态的小部件,第一个标题为 MyApp,它在 ListView 构建器中显示员工列表。第二个有状态的小部件名为 ActionButton,它也是一个有状态的小部件。

ActionButton 小部件返回一个警报对话框。在警报对话框中,我可以通过输入员工姓名和薪水来添加新员工。

问题是,为了显示新添加的员工,我必须热重载应用程序。有没有办法通知 MyApp 小部件已添加新员工,然后在 ListView 构建器中显示新添加的员工。

下面是 MyApp Widget 的代码:

                  import 'package:flutter/material.dart';

            import './database_helper.dart';
            import './floating_action_button.dart';

            void main() async {
              DatabaseHelper databaseHelper = new DatabaseHelper();
              List employees = [];
              employees = await databaseHelper.getAllEmployees();

              runApp(MyApp(employees));
            }

            class MyApp extends StatefulWidget {
              final List employees;

              MyApp(this.employees);

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

            class _MyAppState extends State<MyApp> {
              List employees = [];

              @override
              void initState() {
                super.initState();
                employees = widget.employees;
              }

              @override
              Widget build(BuildContext context) {
                return MaterialApp(
                  home: Scaffold(
                    appBar: AppBar(
                      title: Text("Employees"),
                    ),
                    body: Container(
                      child: ListView.builder(
                        itemCount: employees.length,
                        itemBuilder: (BuildContext context, int index) {
                          return new Card(
                            child: ListTile(
                              title: Text(employees[index]["empName"]),
                              subtitle: Text(
                                employees[index]["empSalary"].toString()),
                              trailing: RaisedButton(
                                onPressed: () {
                                  removeEmployee(
                                     employees[index]["id"], index);
                                },
                                child: Icon(
                                  Icons.remove,
                                  color: Colors.white,
                                ),
                                shape: CircleBorder(),
                                color: Theme.of(context).primaryColor,
                              ),
                            ),
                          );
                        },
                      ),
                    ),
                    floatingActionButton: ActionButton(),
                  ),
                );
              }

              Future<int> removeEmployee(int id, int index) async {
                DatabaseHelper databaseHelper = new DatabaseHelper();
                var result = await databaseHelper.deleteEmployee(id);
                if (result == 1) {
                  setState(() {
                    employees.removeAt(index);
                  });
                }
                return result;
              }
            }

最后但同样重要的是,ActionButton 代码:

    import 'package:employees/database_helper.dart';
    import 'package:employees/employee.dart';
    import 'package:flutter/material.dart';

    class ActionButton extends StatefulWidget {
      @override
      _ActionButtonState createState() => _ActionButtonState();
    }

    class _ActionButtonState extends State<ActionButton> {
      var _employeeNameController = new TextEditingController();
      var _employeeSalaryController = new TextEditingController();

      @override
      Widget build(BuildContext context) {
        return FloatingActionButton(
          child: Icon(
            Icons.add,
            color: Colors.white,
          ),
          onPressed: () {
            showDialog(
              context: context,
              builder: (_) {
                return AlertDialog(
                  title: Text("Add New Employees"),
                  content: Column(
                    children: <Widget>[
                      TextField(
                        controller: _employeeNameController,
                      ),
                      TextField(
                        controller: _employeeSalaryController,
                      ),
                    ],
                  ),
                  actions: <Widget>[
                    RaisedButton(
                      onPressed: () {
                        setState(
                          () {
                            addNewEmployee();
                          },
                        );
                      },
                      child: Text("Add Employee"),
                    ),
                  ],
                );
              },
            );
          },
        );
      }

      void addNewEmployee() async {
        DatabaseHelper databaseHelper = new DatabaseHelper();
        Employee employee = new Employee(
              _employeeNameController.text,
              int.parse(_employeeSalaryController.text));
        await databaseHelper.insertEmployee(employee);
      }
    }

感谢您的帮助。 最好的问候

【问题讨论】:

标签: mobile dart flutter


【解决方案1】:

看看这个。 Flutter State Management

目前有三种管理状态的方法:SetState()、InheritedWidget 和 BLoC。

根据我的经验,如果您想要的是小部件重绘,那么 BLoC 是最好的。这是最直接的方法。

定义 BLoC 和提供者:

import 'package:flutter/material.dart';
import 'dart:async';
import 'package:rxdart/rxdart.dart';

class EmployeeProvider extends InheritedWidget {
  final employeeBloc=EmployeeBloc();
  EmployeeProvider({Key key, @required Widget child,})
      : assert(child != null),
        super(key: key, child: child);

  static EmployeeBloc of(BuildContext context) {
    return (context.inheritFromWidgetOfExactType(EmployeeProvider) as EmployeeProvider).employeeBloc;
  }

  @override
  bool updateShouldNotify(EmployeeProvider old)=>true;
}

class EmployeeBloc{
  //This is the output interface of Bloc
  ValueObservable<List<Employee>> get list => _list.stream;//seedValue: '/'
  final _list = BehaviorSubject<List<Employee>>();//seedValue: '/'

  // This is the input interface of Bloc
  Sink<List<Employee>> get listChange => _listChangeController.sink;
  final _listChangeController = StreamController<List<Employee>>();

  EmployeeBloc(){
    _listChangeController.stream.listen(_handleListChange);
  }
  // This is the logic handling input
  void _handleListChange(List<Employee> newList){
    _list.add(newList);
  }
}

用法:

  1. 将整个应用程序(或感兴趣的部分)包装在 EmployeeProvider 中
  2. 每当需要更新列表时

    EmployeeProvider.of(context).listChange.add(NewEmployeeList);
    
  3. 将需要重绘的小部件包装在 StreamBuilder 中

    StreamBuilder<List<Employee>>( stream: EmployeeProvider.of(context).list, builder: (context, snapshot)=>ListView( children: snapshot.data.map(mapDataToListTile), ), );

每当流接收到新值时,StreamBuilder 内的小部件都会立即重绘。

【讨论】:

  • 需要关闭控制器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-01
  • 2020-10-07
  • 1970-01-01
  • 1970-01-01
  • 2021-10-21
  • 2021-07-02
  • 2021-03-01
相关资源
最近更新 更多