CupertinoTabBar 和 BottomNavigationBarItem UI 未使用 ChangeNotifierProvider 更新
CupertinoTabBar and BottomNavigationBarItem UI not updating with ChangeNotifierProvider
我正在使用 Flutter Provider
包来管理 CupertionTabBar
的 currentIndex
状态。我这样做而不是使用 StatefulWidget
的 setState
因为我想以编程方式从选项卡视图页面中更新当前活动选项卡。
这是应用代码:
import 'package:flutter/cupertino.dart';
import 'package:provider/provider.dart';
void main() {
runApp(const App());
}
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return CupertinoApp(
theme: const CupertinoThemeData(
brightness: Brightness.light,
),
home: ChangeNotifierProvider(
create: (context) => AppState(),
child: const TabsPage(),
),
);
}
}
class TabsPage extends StatelessWidget {
const TabsPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Consumer<AppState>(
builder: (context, appState, child) {
return CupertinoTabScaffold(
tabBar: CupertinoTabBar(
backgroundColor: CupertinoColors.white,
currentIndex: appState.currentTabIndex,
onTap: (index) => appState.currentTabIndex = index,
items: const [
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.house),
activeIcon: Icon(CupertinoIcons.house_fill),
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.play_rectangle),
activeIcon: Icon(CupertinoIcons.play_rectangle_fill),
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.heart),
activeIcon: Icon(CupertinoIcons.heart_fill),
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.music_albums),
activeIcon: Icon(CupertinoIcons.music_albums_fill),
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.ellipsis_circle),
activeIcon: Icon(CupertinoIcons.ellipsis_circle_fill),
),
],
),
tabBuilder: (context, index) {
return const TabPage();
},
);
},
);
}
}
class TabPage extends StatelessWidget {
const TabPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return CupertinoTabView(
builder: (context) => Consumer<AppState>(
builder: (context, appState, child) => Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Current Tab: ${appState.currentTabIndex}'),
const SizedBox(height: 8.0),
...List.generate(
5,
(index) => Padding(
padding: const EdgeInsets.all(8.0),
child: CupertinoButton.filled(
child: Text('Go to tab $index'),
onPressed: () => appState.currentTabIndex = index,
),
),
),
],
),
),
),
);
}
}
class AppState extends ChangeNotifier {
int _currentTabIndex = 0;
int get currentTabIndex => _currentTabIndex;
set currentTabIndex(int index) {
_currentTabIndex = index;
notifyListeners();
}
}
检查 DartPad 上的实时代码和结果。
如您所见,虽然 AppState.currentTabIndex
正在更新并反映在 Text
小部件中,但当前活动的 BottomNavigationBarItem
UI 没有更新。
感谢您的帮助。
如CupertinoTabScaffold
docs中所述tabBar
属性:
The CupertinoTabBar.currentIndex is only used to initialize a
CupertinoTabController when no controller is provided. Subsequently
providing a different CupertinoTabBar.currentIndex does not affect the
scaffold or the tab bar's active tab index. To programmatically change
the active tab index, use a CupertinoTabController.
If CupertinoTabBar.onTap is provided, it will still be called.
CupertinoTabScaffold automatically also listen to the
CupertinoTabBar's onTap to change the controller's index and change
the actively displayed tab in CupertinoTabScaffold's own main content
area.
因此,在 AppState
中保存 CupertinoTabController
的实例并在其上更新 index
有效:
import 'package:flutter/cupertino.dart';
import 'package:provider/provider.dart';
void main() {
runApp(const App());
}
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return CupertinoApp(
theme: const CupertinoThemeData(
brightness: Brightness.light,
),
home: ChangeNotifierProvider(
create: (context) => AppState(),
child: const TabsPage(),
),
);
}
}
class TabsPage extends StatelessWidget {
const TabsPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final appState = Provider.of<AppState>(context, listen: false);
return CupertinoTabScaffold(
controller: appState.tabController,
tabBar: CupertinoTabBar(
backgroundColor: CupertinoColors.white,
items: const [
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.house),
activeIcon: Icon(CupertinoIcons.house_fill),
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.play_rectangle),
activeIcon: Icon(CupertinoIcons.play_rectangle_fill),
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.heart),
activeIcon: Icon(CupertinoIcons.heart_fill),
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.music_albums),
activeIcon: Icon(CupertinoIcons.music_albums_fill),
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.ellipsis_circle),
activeIcon: Icon(CupertinoIcons.ellipsis_circle_fill),
),
],
),
tabBuilder: (context, index) {
return const TabPage();
},
);
}
}
class TabPage extends StatelessWidget {
const TabPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return CupertinoTabView(
builder: (context) {
final appState = Provider.of<AppState>(context, listen: false);
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Current Tab: ${appState.tabController.index}'),
const SizedBox(height: 8.0),
...List.generate(
5,
(index) => Padding(
padding: const EdgeInsets.all(8.0),
child: CupertinoButton.filled(
child: Text('Go to tab $index'),
onPressed: () => appState.tabController.index = index,
),
),
),
],
),
);
},
);
}
}
class AppState extends ChangeNotifier {
final tabController = CupertinoTabController();
@override
void dispose() {
tabController.dispose();
super.dispose();
}
}
我正在使用 Flutter Provider
包来管理 CupertionTabBar
的 currentIndex
状态。我这样做而不是使用 StatefulWidget
的 setState
因为我想以编程方式从选项卡视图页面中更新当前活动选项卡。
这是应用代码:
import 'package:flutter/cupertino.dart';
import 'package:provider/provider.dart';
void main() {
runApp(const App());
}
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return CupertinoApp(
theme: const CupertinoThemeData(
brightness: Brightness.light,
),
home: ChangeNotifierProvider(
create: (context) => AppState(),
child: const TabsPage(),
),
);
}
}
class TabsPage extends StatelessWidget {
const TabsPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Consumer<AppState>(
builder: (context, appState, child) {
return CupertinoTabScaffold(
tabBar: CupertinoTabBar(
backgroundColor: CupertinoColors.white,
currentIndex: appState.currentTabIndex,
onTap: (index) => appState.currentTabIndex = index,
items: const [
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.house),
activeIcon: Icon(CupertinoIcons.house_fill),
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.play_rectangle),
activeIcon: Icon(CupertinoIcons.play_rectangle_fill),
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.heart),
activeIcon: Icon(CupertinoIcons.heart_fill),
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.music_albums),
activeIcon: Icon(CupertinoIcons.music_albums_fill),
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.ellipsis_circle),
activeIcon: Icon(CupertinoIcons.ellipsis_circle_fill),
),
],
),
tabBuilder: (context, index) {
return const TabPage();
},
);
},
);
}
}
class TabPage extends StatelessWidget {
const TabPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return CupertinoTabView(
builder: (context) => Consumer<AppState>(
builder: (context, appState, child) => Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Current Tab: ${appState.currentTabIndex}'),
const SizedBox(height: 8.0),
...List.generate(
5,
(index) => Padding(
padding: const EdgeInsets.all(8.0),
child: CupertinoButton.filled(
child: Text('Go to tab $index'),
onPressed: () => appState.currentTabIndex = index,
),
),
),
],
),
),
),
);
}
}
class AppState extends ChangeNotifier {
int _currentTabIndex = 0;
int get currentTabIndex => _currentTabIndex;
set currentTabIndex(int index) {
_currentTabIndex = index;
notifyListeners();
}
}
检查 DartPad 上的实时代码和结果。
如您所见,虽然 AppState.currentTabIndex
正在更新并反映在 Text
小部件中,但当前活动的 BottomNavigationBarItem
UI 没有更新。
感谢您的帮助。
如CupertinoTabScaffold
docs中所述tabBar
属性:
The CupertinoTabBar.currentIndex is only used to initialize a CupertinoTabController when no controller is provided. Subsequently providing a different CupertinoTabBar.currentIndex does not affect the scaffold or the tab bar's active tab index. To programmatically change the active tab index, use a CupertinoTabController.
If CupertinoTabBar.onTap is provided, it will still be called. CupertinoTabScaffold automatically also listen to the CupertinoTabBar's onTap to change the controller's index and change the actively displayed tab in CupertinoTabScaffold's own main content area.
因此,在 AppState
中保存 CupertinoTabController
的实例并在其上更新 index
有效:
import 'package:flutter/cupertino.dart';
import 'package:provider/provider.dart';
void main() {
runApp(const App());
}
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return CupertinoApp(
theme: const CupertinoThemeData(
brightness: Brightness.light,
),
home: ChangeNotifierProvider(
create: (context) => AppState(),
child: const TabsPage(),
),
);
}
}
class TabsPage extends StatelessWidget {
const TabsPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final appState = Provider.of<AppState>(context, listen: false);
return CupertinoTabScaffold(
controller: appState.tabController,
tabBar: CupertinoTabBar(
backgroundColor: CupertinoColors.white,
items: const [
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.house),
activeIcon: Icon(CupertinoIcons.house_fill),
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.play_rectangle),
activeIcon: Icon(CupertinoIcons.play_rectangle_fill),
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.heart),
activeIcon: Icon(CupertinoIcons.heart_fill),
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.music_albums),
activeIcon: Icon(CupertinoIcons.music_albums_fill),
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.ellipsis_circle),
activeIcon: Icon(CupertinoIcons.ellipsis_circle_fill),
),
],
),
tabBuilder: (context, index) {
return const TabPage();
},
);
}
}
class TabPage extends StatelessWidget {
const TabPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return CupertinoTabView(
builder: (context) {
final appState = Provider.of<AppState>(context, listen: false);
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Current Tab: ${appState.tabController.index}'),
const SizedBox(height: 8.0),
...List.generate(
5,
(index) => Padding(
padding: const EdgeInsets.all(8.0),
child: CupertinoButton.filled(
child: Text('Go to tab $index'),
onPressed: () => appState.tabController.index = index,
),
),
),
],
),
);
},
);
}
}
class AppState extends ChangeNotifier {
final tabController = CupertinoTabController();
@override
void dispose() {
tabController.dispose();
super.dispose();
}
}