デモアドレス: https://github.com/iotjin/jh_flutter_demo
代码不定时更新,请前往github查看最新代码
参考:
Flutter下部のタブスイッチでページ状態を維持
フラッターを完璧に解決 Tab/TabBar切り替え、TabViewページ状態で
Flutterを維持 ページ切り替え後も元のページ状態を維持する3つの方法
順序
APP メイン インターフェイスの各モジュールのページは、通常、下部のタブ バー + 上部のナビゲーション + 中央のコンテンツで構成されます。通常の状況では、各モジュールのページを 1 回初期化するだけで十分であり、毎回更新するのはあまり友好的ではありません。
タブバーでページの状態を維持する方法は次のとおりです
/// 通过 PageView + AutomaticKeepAliveClientMixin 保持页面状态(进到哪个页面,哪个页面开始初始化)
/// 在需要保持页面状态的子页面State中,继承AutomaticKeepAliveClientMixin并重写方法 wantKeepAlive => true
/// 并且它们的[build]方法必须调用super.build(context);
ページに入るたびに更新する必要がある場合は、
Provider
状態管理を追加して
、didChangeDependencies で currentIndex を判断することができます。次のコードは、Provider
状態管理を追加します。
特定のページで tabbar の指定されたページに戻る必要がある場合は
Provider
それに create を追加しmain.dart
、そうでない場合は basetabbar に記述します
方法 1:
- ページの状態を維持するためのサポート
- 変更することで、指定したページからタブバーで指定したインデックスページに戻ることができ
Provider
ますcurrentIndex
(ログアウトする場合は0currentIndex
に変更する)
ページが更新されるたびに
void didChangeDependencies() {
super.didChangeDependencies();
var currentIndex = Provider.of<TabbarProvider>(context).currentIndex;
if (currentIndex == 1) {
_requestData(isShowLoading: true);
}
}
指定したタブバーのページに戻る
JhNavUtils.pushReplacement(context, '/home'); // 返回tabbar 主页面
Provider.of<TabbarProvider>(context, listen: false).currentIndex = 1;
TabbarProvider コード
import 'package:flutter/material.dart';
class TabbarProvider extends ChangeNotifier {
int _currentIndex = 0;
int get currentIndex => _currentIndex;
set currentIndex(int index) {
_currentIndex = index;
notifyListeners();
}
}
main.dart コード
Widget build(BuildContext context) {
JhScreenUtils.init(context);
final Widget app = MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => ThemeProvider()),
ChangeNotifierProvider(create: (_) => TabbarProvider()),
],
child: Consumer<ThemeProvider>(
builder: (_, ThemeProvider provider, __) {
return _buildMaterialApp(provider);
},
));
return app;
}
BaseTabBar コード
/// base_tabbar.dart
///
/// Created by iotjin on 2020/03/08.
/// description: tabbar基类
import 'package:flutter/material.dart';
import 'package:badges/badges.dart';
import 'package:provider/provider.dart';
import '/jh_common/utils/jh_image_utils.dart';
import '/project/configs/colors.dart';
import '/project/provider/tabbar_provider.dart';
import '/project/provider/theme_provider.dart';
import '/project/one/one_page.dart';
import '/project/Two/two_page.dart';
import '/project/Three/three_page.dart';
import '/project/four/four_page.dart';
const double _iconWH = 24.0;
const double _fontSize = 10.0;
class BaseTabBar extends StatefulWidget {
BaseTabBar({
Key? key}) : super(key: key);
_BaseTabBarState createState() => _BaseTabBarState();
}
class _BaseTabBarState extends State<BaseTabBar> {
// int _currentIndex = 0;
List<Widget> _pageList = [OnePage(), TwoPage(), ThreePage(), FourPage()];
PageController _pageController = PageController();
List<BottomNavigationBarItem> getBottomTabs(iconColor) {
return [
BottomNavigationBarItem(
label: '微信',
icon: JhLoadAssetImage('tab/nav_tab_1', width: _iconWH),
activeIcon: JhLoadAssetImage('tab/nav_tab_1_on', width: _iconWH, color: iconColor),
),
BottomNavigationBarItem(
label: '通讯录',
icon: JhLoadAssetImage('tab/nav_tab_2', width: _iconWH),
activeIcon: JhLoadAssetImage('tab/nav_tab_2_on', width: _iconWH, color: iconColor),
),
BottomNavigationBarItem(
label: '发现',
// icon: JhLoadAssetImage('tab/nav_tab_3', width: _iconWH),
activeIcon: JhLoadAssetImage('tab/nav_tab_3_on', width: _iconWH, color: iconColor),
icon: Badge(
padding: EdgeInsets.all(4),
position: BadgePosition.topEnd(top: -4, end: -4),
child: JhLoadAssetImage('tab/nav_tab_3', width: _iconWH)),
// activeIcon: Badge(
// padding: EdgeInsets.all(4),
// position: BadgePosition.topRight(top: -4, right: -4),
// child: JhLoadAssetImage('tab/nav_tab_3_on', width: _iconWH)),
),
BottomNavigationBarItem(
label: '我的',
icon: JhLoadAssetImage('tab/nav_tab_4', width: _iconWH),
activeIcon: JhLoadAssetImage('tab/nav_tab_4_on', width: _iconWH, color: iconColor),
),
];
}
void initState() {
// TODO: implement initState
super.initState();
}
void dispose() {
_pageController.dispose();
super.dispose();
}
Widget build(BuildContext context) {
// TODO: 通过ThemeProvider进行主题管理
final provider = Provider.of<ThemeProvider>(context);
var bgColor = KColors.dynamicColor(context, KColors.kTabBarBgColor, KColors.kTabBarBgDarkColor);
var normalTextColor =
KColors.dynamicColor(context, KColors.kTabBarNormalTextColor, KColors.kTabBarNormalTextDarkColor);
var selectTextColor = KColors.dynamicColor(context, provider.getThemeColor(), KColors.kThemeColor);
var selectIconColor = KColors.dynamicColor(context, provider.getThemeColor(), KColors.kThemeColor);
final tabbarProvider = Provider.of<TabbarProvider>(context);
/// 通过 PageView + AutomaticKeepAliveClientMixin 保持页面状态(进到哪个页面,哪个页面开始初始化)
/// 在需要保持页面状态的子页面State中,继承AutomaticKeepAliveClientMixin并重写方法 wantKeepAlive => true
/// 并且它们的[build]方法必须调用super.build(context);
return Scaffold(
body: PageView(
physics: const NeverScrollableScrollPhysics(), // 禁止滑动
controller: _pageController = PageController(initialPage: tabbarProvider.currentIndex),
children: _pageList,
onPageChanged: (int index) => tabbarProvider.currentIndex = index,
),
bottomNavigationBar: BottomNavigationBar(
backgroundColor: bgColor,
// 未选中颜色
unselectedItemColor: normalTextColor,
// 选中颜色,与fixedColor不能同时设置
// selectedItemColor: selectColor,
// 选中的颜色
fixedColor: selectTextColor,
unselectedFontSize: _fontSize,
selectedFontSize: _fontSize,
// 配置底部BaseTabBar可以有多个按钮
type: BottomNavigationBarType.fixed,
items: getBottomTabs(selectIconColor),
// 配置对应的索引值选中
currentIndex: tabbarProvider.currentIndex,
onTap: (index) => _pageController.jumpToPage(index),
),
);
}
}
方法 2:
タブバーの指定ページに戻る必要がない場合は、
BaseTabBar
メソッドをbuild
次のコードに変更し
main.dart
て削除できます。ChangeNotifierProvider(create: (_) => TabbarProvider()),
Widget build(BuildContext context) {
// TODO: 通过ThemeProvider进行主题管理
final provider = Provider.of<ThemeProvider>(context);
var bgColor = KColors.dynamicColor(context, KColors.kTabBarBgColor, KColors.kTabBarBgDarkColor);
var normalTextColor =
KColors.dynamicColor(context, KColors.kTabBarNormalTextColor, KColors.kTabBarNormalTextDarkColor);
var selectTextColor = KColors.dynamicColor(context, provider.getThemeColor(), KColors.kThemeColor);
var selectIconColor = KColors.dynamicColor(context, provider.getThemeColor(), KColors.kThemeColor);
/// 通过 PageView + AutomaticKeepAliveClientMixin 保持页面状态(进到哪个页面,哪个页面开始初始化)
/// 在需要保持页面状态的子页面State中,继承AutomaticKeepAliveClientMixin并重写方法 wantKeepAlive => true
/// 并且它们的[build]方法必须调用super.build(context);
return ChangeNotifierProvider(
create: (_) => TabbarProvider(),
child: Scaffold(
body: PageView(
physics: const NeverScrollableScrollPhysics(), // 禁止滑动
controller: _pageController,
children: _pageList,
),
bottomNavigationBar: Consumer<TabbarProvider>(builder: (_, provider, __) {
return BottomNavigationBar(
backgroundColor: bgColor,
// 未选中颜色
unselectedItemColor: normalTextColor,
// 选中颜色,与fixedColor不能同时设置
// selectedItemColor: selectColor,
// 选中的颜色
fixedColor: selectTextColor,
unselectedFontSize: _fontSize,
selectedFontSize: _fontSize,
// 配置底部BaseTabBar可以有多个按钮
type: BottomNavigationBarType.fixed,
items: getBottomTabs(selectIconColor),
// 配置对应的索引值选中
currentIndex: provider.currentIndex,
// 配置对应的索引值选中
onTap: (int index) {
setState(() {
// 改变状态
provider.currentIndex = index;
_pageController.jumpToPage(index);
});
},
);
}),
),
);
}
方法 3:
これは、IndexedStack を使用してページの状態を維持するため、またはビルド方法を変更するためです。
/// 使用IndexedStack保持页面状态如下:
/// 这种方式有个小缺点:IndexedStack中管理的子页面在第一次加载时便实例化了所有的子页面State
Widget build(BuildContext context) {
// TODO: 通过ThemeProvider进行主题管理
final provider = Provider.of<ThemeProvider>(context);
var bgColor = KColors.dynamicColor(context, KColors.kTabBarBgColor, KColors.kTabBarBgDarkColor);
var normalTextColor =
KColors.dynamicColor(context, KColors.kTabBarNormalTextColor, KColors.kTabBarNormalTextDarkColor);
var selectTextColor = KColors.dynamicColor(context, provider.getThemeColor(), KColors.kThemeColor);
var selectIconColor = KColors.dynamicColor(context, provider.getThemeColor(), KColors.kThemeColor);
return Scaffold(
body: IndexedStack(
index: _currentIndex,
children: _pageList,
),
bottomNavigationBar: BottomNavigationBar(
backgroundColor: bgColor,
// 未选中颜色
unselectedItemColor: normalTextColor,
// 选中颜色,与fixedColor不能同时设置
// selectedItemColor: selectColor,
// 选中的颜色
fixedColor: selectTextColor,
unselectedFontSize: _fontSize,
selectedFontSize: _fontSize,
// 配置底部BaseTabBar可以有多个按钮
type: BottomNavigationBarType.fixed,
items: getBottomTabs(selectIconColor),
// 配置对应的索引值选中
currentIndex: this._currentIndex,
onTap: (int index) {
setState(() {
// 改变状态
this._currentIndex = index;
});
},
),
);
}