在此 ModalBottomSheet 小部件上方找不到正确的 Provider<X>
Could not find the correct Provider<X> above this ModalBottomSheet Widget
我是 Flutter 的新手,我正在尝试了解如何在用户 Moor
将一些数据保存到 sqlite
table 的应用程序中使用提供者状态管理。我的应用程序是一个任务记录应用程序。当我打开底部 sheet 添加任务时,我的小部件树中出现上述错误。我正在使用 provider: ^4.3.1
class TaskView extends StatelessWidget {
DateTime selectedDate = DateTime.now();
@override
Widget build(BuildContext context) {
return Provider<TaskViewModel>(
create: (_) => TaskViewModel(),
child: Scaffold(
appBar: AppBar(
title: Text('Tasks'),
),
body: Text("Temporary body!"),
floatingActionButton: FloatingActionButton(
onPressed: () {
showMaterialModalBottomSheet(
context: context,
builder: (context, scrollController) => Container(
child: bottomSheet(context),
),
);
},
child: Icon(
Icons.add,
color: Colors.white,
),
backgroundColor: Colors.blueAccent,
)
)
);
}
Widget bottomSheet(BuildContext context) {
return Padding(
padding: EdgeInsets.only(
left: 16.0,
top: 16.0,
right: 16.0,
bottom: 16.0 + MediaQuery.of(context).viewInsets.bottom),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Task',
),
),
SizedBox(height: 8),
TextField(
readOnly: true,
decoration: InputDecoration(
border: OutlineInputBorder(),
suffixIcon: IconButton(
icon: Icon(Icons.date_range, color: Colors.grey),
onPressed: () => _selectDate(context),
),
labelText: 'Date',
),
),
SizedBox(height: 8),
Align(
alignment: Alignment.topRight,
child: context.watch<TaskViewModel>().state == ViewState.IDLE
? FlatButton(
child: Text("Save"),
color: Colors.blueAccent,
textColor: Colors.white,
onPressed: () => _onClickInsertTask(context))
: _loadingButtonChild(context))
],
),
);
}
Widget _loadingButtonChild(BuildContext context) {
return Container(
height: 20,
width: 20,
margin: EdgeInsets.all(5),
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(Colors.white)),
);
}
/// This function is responsible for displaying the date picker when user click
/// on task due date inputFiled
Future<Null> _selectDate(BuildContext context) async {
final DateTime picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(2015, 8),
lastDate: DateTime(2101));
if (picked != null && picked != selectedDate) {
print("Date selected ${selectedDate.toString()}");
}
}
/// This function is responsible for triggering insert task block event
void _onClickInsertTask(BuildContext context) {
var insertTask = TaskData(task: "task", dueDate: selectedDate);
context.read<TaskViewModel>().insertTask(insertTask);
}
}
错误建议检查
- 您尝试阅读的提供商在不同的路线上。
我没有给provider to s route,而是作为直接父视图。
- 您使用的 BuildContext
是您尝试读取的提供商的祖先。
我不明白这是什么意思,但我按照错误中的建议进行了修复。如下图
@override
Widget build(BuildContext context) {
return Provider<TaskViewModel>(
create: (_) => TaskViewModel(),
builder: (context, child) => Scaffold(
appBar: AppBar(
title: Text('Tasks'),
),
body: Text("Temporary body!"),
floatingActionButton: FloatingActionButton(
onPressed: () {
showMaterialModalBottomSheet(
context: context,
builder: (context, scrollController) => Container(
child: bottomSheet(context),
),
);
},
child: Icon(
Icons.add,
color: Colors.white,
),
backgroundColor: Colors.blueAccent,
)));
}
仍然得到同样的错误。这里要注意的另一件事是错误提示如下。
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// we use `builder` to obtain a new `BuildContext` that has access to the provider
builder: (context) {
// No longer throws
return Text(context.watch<Example>()),
}
),
}
但是我找不到 builder: (context)
所以我使用了 builder: (context, child)
。请让我知道我应该改变什么才能让它工作。谢谢。
编辑:
基础模型
class BaseViewModel extends ChangeNotifier {
ViewState _state = ViewState.IDLE;
ViewState get state => _state;
void setState(ViewState viewState) {
_state = viewState;
notifyListeners();
}
}
TaskViewModel
class TaskViewModel extends BaseViewModel{
final TaskRepository _repository = TaskRepository();
Resource<int> insertTaskStatus;
Future<void> insertTask(TaskData task) async {
setState(ViewState.PROCESSING);
var tasksCompanion = TasksCompanion(task: Value(task.task),dueDate: Value(task.dueDate));
insertTaskStatus = await _repository.insertTask(tasksCompanion);
setState(ViewState.COMPLETED);
}
}
虽然你在 provider
包裹的 Scaffold
中调用 showMaterialModalBottomSheet
,但 provider
并不在 TaskView
的 [=11= 之上] 和 modalBottomSheet
。为什么?
The provider you are trying to read is in a different route.
因此,modalBottomSheet
似乎在另一个 route
上,上面没有 provider
。如果你看一下 showModalBottomSheet 的实现,你会看到:
return Navigator.of(context, rootNavigator: useRootNavigator).push(_ModalBottomSheetRoute<T>(....);
很明显,这是一个新的 route
。因此,要访问 provider
,它应该位于 routes
之上。由于 modalBottomSheet
route
由 MaterialApp
管理,因此您必须将 provider
放在 MaterialApp
之上。
Provider
默认使用 lazy loading
。因此,对象是在需要时创建的,而不是在应用程序启动时创建的。但是,如果您不希望出现这种情况,您可以单独设置 lazy: false
。有关详细信息,请查看 offical docs.
我是 Flutter 的新手,我正在尝试了解如何在用户 Moor
将一些数据保存到 sqlite
table 的应用程序中使用提供者状态管理。我的应用程序是一个任务记录应用程序。当我打开底部 sheet 添加任务时,我的小部件树中出现上述错误。我正在使用 provider: ^4.3.1
class TaskView extends StatelessWidget {
DateTime selectedDate = DateTime.now();
@override
Widget build(BuildContext context) {
return Provider<TaskViewModel>(
create: (_) => TaskViewModel(),
child: Scaffold(
appBar: AppBar(
title: Text('Tasks'),
),
body: Text("Temporary body!"),
floatingActionButton: FloatingActionButton(
onPressed: () {
showMaterialModalBottomSheet(
context: context,
builder: (context, scrollController) => Container(
child: bottomSheet(context),
),
);
},
child: Icon(
Icons.add,
color: Colors.white,
),
backgroundColor: Colors.blueAccent,
)
)
);
}
Widget bottomSheet(BuildContext context) {
return Padding(
padding: EdgeInsets.only(
left: 16.0,
top: 16.0,
right: 16.0,
bottom: 16.0 + MediaQuery.of(context).viewInsets.bottom),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Task',
),
),
SizedBox(height: 8),
TextField(
readOnly: true,
decoration: InputDecoration(
border: OutlineInputBorder(),
suffixIcon: IconButton(
icon: Icon(Icons.date_range, color: Colors.grey),
onPressed: () => _selectDate(context),
),
labelText: 'Date',
),
),
SizedBox(height: 8),
Align(
alignment: Alignment.topRight,
child: context.watch<TaskViewModel>().state == ViewState.IDLE
? FlatButton(
child: Text("Save"),
color: Colors.blueAccent,
textColor: Colors.white,
onPressed: () => _onClickInsertTask(context))
: _loadingButtonChild(context))
],
),
);
}
Widget _loadingButtonChild(BuildContext context) {
return Container(
height: 20,
width: 20,
margin: EdgeInsets.all(5),
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(Colors.white)),
);
}
/// This function is responsible for displaying the date picker when user click
/// on task due date inputFiled
Future<Null> _selectDate(BuildContext context) async {
final DateTime picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(2015, 8),
lastDate: DateTime(2101));
if (picked != null && picked != selectedDate) {
print("Date selected ${selectedDate.toString()}");
}
}
/// This function is responsible for triggering insert task block event
void _onClickInsertTask(BuildContext context) {
var insertTask = TaskData(task: "task", dueDate: selectedDate);
context.read<TaskViewModel>().insertTask(insertTask);
}
}
错误建议检查
- 您尝试阅读的提供商在不同的路线上。
我没有给provider to s route,而是作为直接父视图。
- 您使用的 BuildContext
是您尝试读取的提供商的祖先。
我不明白这是什么意思,但我按照错误中的建议进行了修复。如下图
@override
Widget build(BuildContext context) {
return Provider<TaskViewModel>(
create: (_) => TaskViewModel(),
builder: (context, child) => Scaffold(
appBar: AppBar(
title: Text('Tasks'),
),
body: Text("Temporary body!"),
floatingActionButton: FloatingActionButton(
onPressed: () {
showMaterialModalBottomSheet(
context: context,
builder: (context, scrollController) => Container(
child: bottomSheet(context),
),
);
},
child: Icon(
Icons.add,
color: Colors.white,
),
backgroundColor: Colors.blueAccent,
)));
}
仍然得到同样的错误。这里要注意的另一件事是错误提示如下。
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// we use `builder` to obtain a new `BuildContext` that has access to the provider
builder: (context) {
// No longer throws
return Text(context.watch<Example>()),
}
),
}
但是我找不到 builder: (context)
所以我使用了 builder: (context, child)
。请让我知道我应该改变什么才能让它工作。谢谢。
编辑:
基础模型
class BaseViewModel extends ChangeNotifier {
ViewState _state = ViewState.IDLE;
ViewState get state => _state;
void setState(ViewState viewState) {
_state = viewState;
notifyListeners();
}
}
TaskViewModel
class TaskViewModel extends BaseViewModel{
final TaskRepository _repository = TaskRepository();
Resource<int> insertTaskStatus;
Future<void> insertTask(TaskData task) async {
setState(ViewState.PROCESSING);
var tasksCompanion = TasksCompanion(task: Value(task.task),dueDate: Value(task.dueDate));
insertTaskStatus = await _repository.insertTask(tasksCompanion);
setState(ViewState.COMPLETED);
}
}
虽然你在 provider
包裹的 Scaffold
中调用 showMaterialModalBottomSheet
,但 provider
并不在 TaskView
的 [=11= 之上] 和 modalBottomSheet
。为什么?
The provider you are trying to read is in a different route.
因此,modalBottomSheet
似乎在另一个 route
上,上面没有 provider
。如果你看一下 showModalBottomSheet 的实现,你会看到:
return Navigator.of(context, rootNavigator: useRootNavigator).push(_ModalBottomSheetRoute<T>(....);
很明显,这是一个新的 route
。因此,要访问 provider
,它应该位于 routes
之上。由于 modalBottomSheet
route
由 MaterialApp
管理,因此您必须将 provider
放在 MaterialApp
之上。
Provider
默认使用 lazy loading
。因此,对象是在需要时创建的,而不是在应用程序启动时创建的。但是,如果您不希望出现这种情况,您可以单独设置 lazy: false
。有关详细信息,请查看 offical docs.