Флаттер передает данные между виджетами?
У меня есть два виджета с состоянием, первый под названием MyApp, который отображает список сотрудников в построителе ListView. Второй виджет с состоянием называется ActionButton, который также является виджетом с полным состоянием.
Виджет ActionButton возвращает диалог оповещения. В диалоге оповещения я могу добавить нового сотрудника, введя имя сотрудника и зарплату.
Проблема в том, чтобы показать вновь добавленного сотрудника, мне нужно перезагрузить приложение. Есть ли способ сообщить виджету MyApp, что добавлен новый сотрудник, а затем отобразить нового добавленного сотрудника в построителе ListView.
Ниже приведен код для виджета MyApp:
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);
}
}
Спасибо за помощь. С уважением
1 ответ
Проверь это. Флаттер Государственное управление
В настоящее время существует три способа управления состоянием: 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);
}
}
Использование:
- Оберните все приложение (или заинтересованную часть) в EmployeeProvider
Всякий раз, когда нужно обновить список
EmployeeProvider.of(context).listChange.add(NewEmployeeList);
Оберните виджет, который должен быть перерисован в StreamBuilder
StreamBuilder<List<Employee>>( stream: EmployeeProvider.of(context).list, builder: (context, snapshot)=>ListView( children: snapshot.data.map(mapDataToListTile), ), );
Всякий раз, когда поток получает новое значение, виджет внутри StreamBuilder немедленно перерисовывается.