Flutter - アプリのメイン インターフェース Tabbar はページの状態を維持します

デモアドレス: 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;
        });
      },
    ),
  );
}

Supongo que te gusta

Origin blog.csdn.net/iotjin/article/details/126870716
Recomendado
Clasificación