尝试为我的状态使用带有嵌套 BottomNavigation Bar 的提供程序时出现问题 - Flutter
Problem trying to use provider with nested BottomNavigation Bar for my state- Flutter
我正在尝试通过提供商学习正确的状态管理,但我遇到了一个问题,我在这里遇到了麻烦。据我所知,我正在按照三个单独的提供商教程中的说明进行所有操作。我也成功地将它用于我的数据表,没有任何问题。但是,当我尝试为小部件树上的 BottomNavigationBar 和 appBar 使用提供程序时,我不断收到错误消息和失败。
我想让我的底部导航栏与我的“零屏幕”状态分开。所以我根据索引设置一个底部导航栏按钮按下的 int,这应该更新我的 GlobalData pageSelection 索引。然后我在三元运算符的树上访问它。但是我收到一个奇怪的错误,说它不在小部件树中...
我尝试按照错误建议进行操作,但没有成功。
感谢任何帮助!
import 'package:flutter/material.dart';
class GlobalData extends ChangeNotifier {
int pageSelectionIndex = 0;
void updatePageSelection(int index) {
pageSelectionIndex = index;
notifyListeners();
}
}
底部导航栏
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:fp_provider_demo_one/models/global_data.dart';
import 'package:fp_provider_demo_one/screens/balance_screen.dart';
import 'package:fp_provider_demo_one/screens/subtract_screen.dart';
import 'package:fp_provider_demo_one/screens/add_screen.dart';
import 'package:fp_provider_demo_one/screens/inquiry_screen.dart';
import 'package:provider/provider.dart';
// ignore: must_be_immutable
class BottomNavBar extends StatefulWidget {
@override
_BottomNavBarState createState() => _BottomNavBarState();
}
class _BottomNavBarState extends State<BottomNavBar> {
int _currentTabIndex = 0;
@override
Widget build(BuildContext context) {
final _tabPages = <Widget>[
AddScreen(),
SubtractScreen(),
BalanceScreen(),
InquiryScreen()
];
final _navBarItems = <BottomNavigationBarItem>[
const BottomNavigationBarItem(
icon: Icon(Icons.add_circle), label: 'Add'),
const BottomNavigationBarItem(
icon: Icon(Icons.remove_circle), label: 'Subtract'),
const BottomNavigationBarItem(
icon: Icon(Icons.grid_on_rounded), label: 'Balance'),
const BottomNavigationBarItem(
icon: Icon(Icons.show_chart), label: 'Inquiry'),
];
assert(_tabPages.length == _navBarItems.length);
final navBar = BottomNavigationBar(
items: _navBarItems,
showUnselectedLabels: true,
showSelectedLabels: true,
unselectedItemColor: Colors.grey,
selectedItemColor: Colors.orange,
currentIndex: _currentTabIndex,
type: BottomNavigationBarType.fixed,
onTap: (int index) {
Provider.of<GlobalData>(context).updatePageSelection(index);
setState(() {
_currentTabIndex = index;
});
},
);
return Scaffold(
body: _tabPages[_currentTabIndex],
bottomNavigationBar: navBar,
);
}
}
零屏:
///
///
/// Holds bottom nav bar which in turn switches through screens
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:fp_provider_demo_one/models/global_data.dart';
import 'package:fp_provider_demo_one/widgets/bottom_nav_bar.dart';
import 'package:provider/provider.dart';
class ZeroScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
int _selectedIndex = Provider.of<GlobalData>(context).pageSelectionIndex;
return Scaffold(
appBar: AppBar(
title: (_selectedIndex == 0)
? Text('Add')
: (_selectedIndex == 1)
? Text('Subtract')
: (_selectedIndex == 2)
? Text('Balance')
: Text('Inquiry'),
backgroundColor: (_selectedIndex == 0)
? Colors.green
: (_selectedIndex == 1)
? Colors.red
: (_selectedIndex == 2)
? Colors.blue
: Colors.orange,
),
bottomNavigationBar: BottomNavBar(),
);
}
}
错误:
======== Exception caught by gesture ===============================================================
The following assertion was thrown while handling a gesture:
Tried to listen to a value exposed with provider, from outside of the widget tree.
This is likely caused by an event handler (like a button's onPressed) that called
Provider.of without passing `listen: false`.
To fix, write:
Provider.of<GlobalData>(context, listen: false);
It is unsupported because may pointlessly rebuild the widget associated to the
event handler, when the widget tree doesn't care about the value.
The context used was: BottomNavBar(state: _BottomNavBarState#38ad7)
'package:provider/src/provider.dart':
Failed assertion: line 262 pos 7: 'context.owner.debugBuilding ||
listen == false ||
debugIsInInheritedProviderUpdate'
When the exception was thrown, this was the stack:
#2 Provider.of (package:provider/src/provider.dart:262:7)
#3 _BottomNavBarState.build.<anonymous closure> (package:fp_provider_demo_one/widgets/bottom_nav_bar.dart:49:18)
#4 _BottomNavigationBarState._createTiles.<anonymous closure> (package:flutter/src/material/bottom_navigation_bar.dart:974:26)
#5 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:991:20)
#6 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
...
Handler: "onTap"
Recognizer: TapGestureRecognizer#035fc
debugOwner: GestureDetector
state: ready
won arena
finalPosition: Offset(144.0, 783.0)
finalLocalPosition: Offset(46.5, 21.5)
button: 1
sent tap down
====================================================================================================
你试过在 onTap 之外声明你的 provider 变量吗?比如:
final provider = Provider.of<GlobalData>(context);
onTap:(index){
provider.updatePageSelection(index);
}
另一种可能性是 context
无法在 onTap
中正确访问,正如它在日志中所说,您应该在声明提供商时设置 listen: false
,如:
Provider.of<GlobalData>(context, listen: false);
您可以复制粘贴 运行 下面的完整代码
第 1 步:使用 Provider.of<GlobalData>(context, listen: false).updatePageSelection
onTap: (int index) {
Provider.of<GlobalData>(context, listen: false)
.updatePageSelection(index);
第 2 步:将 ChangeNotifierProvider
放入 main()
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => GlobalData(),
child: MyApp(),
),
);
}
工作演示
完整代码
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class GlobalData extends ChangeNotifier {
int pageSelectionIndex = 0;
void updatePageSelection(int index) {
pageSelectionIndex = index;
notifyListeners();
}
}
class BottomNavBar extends StatefulWidget {
@override
_BottomNavBarState createState() => _BottomNavBarState();
}
class _BottomNavBarState extends State<BottomNavBar> {
int _currentTabIndex = 0;
@override
Widget build(BuildContext context) {
final _tabPages = <Widget>[
AddScreen(),
SubtractScreen(),
BalanceScreen(),
InquiryScreen()
];
final _navBarItems = <BottomNavigationBarItem>[
const BottomNavigationBarItem(icon: Icon(Icons.add_circle), label: 'Add'),
const BottomNavigationBarItem(
icon: Icon(Icons.remove_circle), label: 'Subtract'),
const BottomNavigationBarItem(
icon: Icon(Icons.grid_on_rounded), label: 'Balance'),
const BottomNavigationBarItem(
icon: Icon(Icons.show_chart), label: 'Inquiry'),
];
assert(_tabPages.length == _navBarItems.length);
final navBar = BottomNavigationBar(
items: _navBarItems,
showUnselectedLabels: true,
showSelectedLabels: true,
unselectedItemColor: Colors.grey,
selectedItemColor: Colors.orange,
currentIndex: _currentTabIndex,
type: BottomNavigationBarType.fixed,
onTap: (int index) {
Provider.of<GlobalData>(context, listen: false)
.updatePageSelection(index);
setState(() {
_currentTabIndex = index;
});
},
);
return Scaffold(
body: _tabPages[_currentTabIndex],
bottomNavigationBar: navBar,
);
}
}
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => GlobalData(),
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: ZeroScreen(),
);
}
}
class ZeroScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
int _selectedIndex = Provider.of<GlobalData>(context).pageSelectionIndex;
return Scaffold(
appBar: AppBar(
title: (_selectedIndex == 0)
? Text('Add')
: (_selectedIndex == 1)
? Text('Subtract')
: (_selectedIndex == 2)
? Text('Balance')
: Text('Inquiry'),
backgroundColor: (_selectedIndex == 0)
? Colors.green
: (_selectedIndex == 1)
? Colors.red
: (_selectedIndex == 2)
? Colors.blue
: Colors.orange,
),
bottomNavigationBar: BottomNavBar(),
);
}
}
class AddScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(child: Text("AddScreen"));
}
}
class SubtractScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(child: Text("SubtractScreen"));
}
}
class BalanceScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(child: Text("BalanceScreen"));
}
}
class InquiryScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(child: Text("InquiryScreen"));
}
}
我正在尝试通过提供商学习正确的状态管理,但我遇到了一个问题,我在这里遇到了麻烦。据我所知,我正在按照三个单独的提供商教程中的说明进行所有操作。我也成功地将它用于我的数据表,没有任何问题。但是,当我尝试为小部件树上的 BottomNavigationBar 和 appBar 使用提供程序时,我不断收到错误消息和失败。
我想让我的底部导航栏与我的“零屏幕”状态分开。所以我根据索引设置一个底部导航栏按钮按下的 int,这应该更新我的 GlobalData pageSelection 索引。然后我在三元运算符的树上访问它。但是我收到一个奇怪的错误,说它不在小部件树中...
我尝试按照错误建议进行操作,但没有成功。
感谢任何帮助!
import 'package:flutter/material.dart';
class GlobalData extends ChangeNotifier {
int pageSelectionIndex = 0;
void updatePageSelection(int index) {
pageSelectionIndex = index;
notifyListeners();
}
}
底部导航栏
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:fp_provider_demo_one/models/global_data.dart';
import 'package:fp_provider_demo_one/screens/balance_screen.dart';
import 'package:fp_provider_demo_one/screens/subtract_screen.dart';
import 'package:fp_provider_demo_one/screens/add_screen.dart';
import 'package:fp_provider_demo_one/screens/inquiry_screen.dart';
import 'package:provider/provider.dart';
// ignore: must_be_immutable
class BottomNavBar extends StatefulWidget {
@override
_BottomNavBarState createState() => _BottomNavBarState();
}
class _BottomNavBarState extends State<BottomNavBar> {
int _currentTabIndex = 0;
@override
Widget build(BuildContext context) {
final _tabPages = <Widget>[
AddScreen(),
SubtractScreen(),
BalanceScreen(),
InquiryScreen()
];
final _navBarItems = <BottomNavigationBarItem>[
const BottomNavigationBarItem(
icon: Icon(Icons.add_circle), label: 'Add'),
const BottomNavigationBarItem(
icon: Icon(Icons.remove_circle), label: 'Subtract'),
const BottomNavigationBarItem(
icon: Icon(Icons.grid_on_rounded), label: 'Balance'),
const BottomNavigationBarItem(
icon: Icon(Icons.show_chart), label: 'Inquiry'),
];
assert(_tabPages.length == _navBarItems.length);
final navBar = BottomNavigationBar(
items: _navBarItems,
showUnselectedLabels: true,
showSelectedLabels: true,
unselectedItemColor: Colors.grey,
selectedItemColor: Colors.orange,
currentIndex: _currentTabIndex,
type: BottomNavigationBarType.fixed,
onTap: (int index) {
Provider.of<GlobalData>(context).updatePageSelection(index);
setState(() {
_currentTabIndex = index;
});
},
);
return Scaffold(
body: _tabPages[_currentTabIndex],
bottomNavigationBar: navBar,
);
}
}
零屏:
///
///
/// Holds bottom nav bar which in turn switches through screens
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:fp_provider_demo_one/models/global_data.dart';
import 'package:fp_provider_demo_one/widgets/bottom_nav_bar.dart';
import 'package:provider/provider.dart';
class ZeroScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
int _selectedIndex = Provider.of<GlobalData>(context).pageSelectionIndex;
return Scaffold(
appBar: AppBar(
title: (_selectedIndex == 0)
? Text('Add')
: (_selectedIndex == 1)
? Text('Subtract')
: (_selectedIndex == 2)
? Text('Balance')
: Text('Inquiry'),
backgroundColor: (_selectedIndex == 0)
? Colors.green
: (_selectedIndex == 1)
? Colors.red
: (_selectedIndex == 2)
? Colors.blue
: Colors.orange,
),
bottomNavigationBar: BottomNavBar(),
);
}
}
错误:
======== Exception caught by gesture ===============================================================
The following assertion was thrown while handling a gesture:
Tried to listen to a value exposed with provider, from outside of the widget tree.
This is likely caused by an event handler (like a button's onPressed) that called
Provider.of without passing `listen: false`.
To fix, write:
Provider.of<GlobalData>(context, listen: false);
It is unsupported because may pointlessly rebuild the widget associated to the
event handler, when the widget tree doesn't care about the value.
The context used was: BottomNavBar(state: _BottomNavBarState#38ad7)
'package:provider/src/provider.dart':
Failed assertion: line 262 pos 7: 'context.owner.debugBuilding ||
listen == false ||
debugIsInInheritedProviderUpdate'
When the exception was thrown, this was the stack:
#2 Provider.of (package:provider/src/provider.dart:262:7)
#3 _BottomNavBarState.build.<anonymous closure> (package:fp_provider_demo_one/widgets/bottom_nav_bar.dart:49:18)
#4 _BottomNavigationBarState._createTiles.<anonymous closure> (package:flutter/src/material/bottom_navigation_bar.dart:974:26)
#5 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:991:20)
#6 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
...
Handler: "onTap"
Recognizer: TapGestureRecognizer#035fc
debugOwner: GestureDetector
state: ready
won arena
finalPosition: Offset(144.0, 783.0)
finalLocalPosition: Offset(46.5, 21.5)
button: 1
sent tap down
====================================================================================================
你试过在 onTap 之外声明你的 provider 变量吗?比如:
final provider = Provider.of<GlobalData>(context);
onTap:(index){
provider.updatePageSelection(index);
}
另一种可能性是 context
无法在 onTap
中正确访问,正如它在日志中所说,您应该在声明提供商时设置 listen: false
,如:
Provider.of<GlobalData>(context, listen: false);
您可以复制粘贴 运行 下面的完整代码
第 1 步:使用 Provider.of<GlobalData>(context, listen: false).updatePageSelection
onTap: (int index) {
Provider.of<GlobalData>(context, listen: false)
.updatePageSelection(index);
第 2 步:将 ChangeNotifierProvider
放入 main()
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => GlobalData(),
child: MyApp(),
),
);
}
工作演示
完整代码
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class GlobalData extends ChangeNotifier {
int pageSelectionIndex = 0;
void updatePageSelection(int index) {
pageSelectionIndex = index;
notifyListeners();
}
}
class BottomNavBar extends StatefulWidget {
@override
_BottomNavBarState createState() => _BottomNavBarState();
}
class _BottomNavBarState extends State<BottomNavBar> {
int _currentTabIndex = 0;
@override
Widget build(BuildContext context) {
final _tabPages = <Widget>[
AddScreen(),
SubtractScreen(),
BalanceScreen(),
InquiryScreen()
];
final _navBarItems = <BottomNavigationBarItem>[
const BottomNavigationBarItem(icon: Icon(Icons.add_circle), label: 'Add'),
const BottomNavigationBarItem(
icon: Icon(Icons.remove_circle), label: 'Subtract'),
const BottomNavigationBarItem(
icon: Icon(Icons.grid_on_rounded), label: 'Balance'),
const BottomNavigationBarItem(
icon: Icon(Icons.show_chart), label: 'Inquiry'),
];
assert(_tabPages.length == _navBarItems.length);
final navBar = BottomNavigationBar(
items: _navBarItems,
showUnselectedLabels: true,
showSelectedLabels: true,
unselectedItemColor: Colors.grey,
selectedItemColor: Colors.orange,
currentIndex: _currentTabIndex,
type: BottomNavigationBarType.fixed,
onTap: (int index) {
Provider.of<GlobalData>(context, listen: false)
.updatePageSelection(index);
setState(() {
_currentTabIndex = index;
});
},
);
return Scaffold(
body: _tabPages[_currentTabIndex],
bottomNavigationBar: navBar,
);
}
}
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => GlobalData(),
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: ZeroScreen(),
);
}
}
class ZeroScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
int _selectedIndex = Provider.of<GlobalData>(context).pageSelectionIndex;
return Scaffold(
appBar: AppBar(
title: (_selectedIndex == 0)
? Text('Add')
: (_selectedIndex == 1)
? Text('Subtract')
: (_selectedIndex == 2)
? Text('Balance')
: Text('Inquiry'),
backgroundColor: (_selectedIndex == 0)
? Colors.green
: (_selectedIndex == 1)
? Colors.red
: (_selectedIndex == 2)
? Colors.blue
: Colors.orange,
),
bottomNavigationBar: BottomNavBar(),
);
}
}
class AddScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(child: Text("AddScreen"));
}
}
class SubtractScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(child: Text("SubtractScreen"));
}
}
class BalanceScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(child: Text("BalanceScreen"));
}
}
class InquiryScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(child: Text("InquiryScreen"));
}
}