1.事象
Provider利用時に、Consumerを2か所に配置( bottom と body の直後)していたところ、
bottom 直後の Consumer のところで、エラーが発生しました(下図)。
(エラー内容)
The argument type ‘Consumer
(修正前):
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Editable and Scrollable Tabs with Add Tab'),
bottom: Consumer<TabManager>(
builder: (context, tabManager, child) {
return TabBar(
controller: tabManager.tabController,
isScrollable: true,
tabs: [
...tabManager.tabTitles.map(
(title) => Tab(
child: SizedBox(
width: 120,
child: TextField(
controller: TextEditingController(text: title),
onSubmitted: (newTitle) {
int index = tabManager.tabTitles.indexOf(title);
tabManager.updateTabTitle(index, newTitle);
},
decoration: const InputDecoration(border: InputBorder.none),
),
),
),
),
const Tab(icon: Icon(Icons.add)),
],
);
},
),
),
body: Consumer<TabManager>(
builder: (context, tabManager, child) {
return TabBarView(
2.修正内容
Consumerウィジェットを
PreferredSize ウィジェットでラップして、AppBarの bottom プロパティに渡しました。
PreferredSize ウィジェットは、PreferredSizeWidget を期待する場所で使用されることを想定しており、内部にあるConsumer ウィジェットを適切に扱うことができます。
(修正後):
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Editable and Scrollable Tabs with Add Tab'),
bottom: PreferredSize(
preferredSize: const Size.fromHeight(48.0),
child: Consumer<TabManager>(
builder: (context, tabManager, child) {
return TabBar(
controller: tabManager.tabController,
isScrollable: true,
tabs: [
...tabManager.tabTitles.map(
(title) => Tab(
child: SizedBox(
width: 120,
child: TextField(
controller: TextEditingController(text: title),
onSubmitted: (newTitle) {
int index = tabManager.tabTitles.indexOf(title);
tabManager.updateTabTitle(index, newTitle);
},
decoration: const InputDecoration(border: InputBorder.none),
),
),
),
),
const Tab(icon: Icon(Icons.add)),
],
);
},
),
),
),
body: Consumer<TabManager>(
builder: (context, tabManager, child) {
return TabBarView(
3.まとめ
provider の Consumer は、bottom 直下配置時とbody直下配置時では扱い方が異なる、という事例でした。