在构建 CupertinoTabScaffold 期间调用 setState() 或 markNeedsBuild()

Posted

技术标签:

【中文标题】在构建 CupertinoTabScaffold 期间调用 setState() 或 markNeedsBuild()【英文标题】:setState() or markNeedsBuild() called during build CupertinoTabScaffold 【发布时间】:2021-06-06 23:22:59 【问题描述】:

我有使用 CupertinoTabScaffold 显示底部导航的代码,我想在其中一个菜单上显示底部对话框,但出现错误

在构建 Builder 时抛出了以下断言(脏,依赖项:[_InheritedTheme,_LocalizationsScope-[GlobalKey #a6d51]]): 构建期间调用的 setState() 或 markNeedsBuild()。

这是我的代码

class AppTab extends StatefulWidget 
final dataUser;
AppTab(this.dataUser);

@override
_AppTabState createState() => _AppTabState(dataUser);


class _AppTabState extends State<AppTab> 
final user;
_AppTabState(this.user);

 @override
Widget build(BuildContext context) 
return BlocListener<AuthenticationBloc, AuthenticationState>(
  listener: (context, state) 
    if (state == AuthenticationState.unauthenticated()) 
      Navigator.pushNamedAndRemoveUntil(context, '/login', (route) => false, arguments: state.loginPageState);
    
  ,
  child: CupertinoTabScaffold(
    controller: tabController,
    tabBar: CupertinoTabBar(
      activeColor: HexColor("#26ADE4"),
      inactiveColor: HexColor("#707070"),
      items: [
        BottomNavigationBarItem(
          label: "Menu 1",
          icon: Image.asset("assets/icon_tab_home.png", height: 25, width: 22),
          activeIcon: Image.asset("assets/icon_tab_home_active.png", height: 25, width: 22),
        ),
        BottomNavigationBarItem(
          label: "Menu 2",
          icon: Image.asset("assets/icon_tab_buat_bill.png", height: 25, width: 22),
          activeIcon: Image.asset("assets/icon_tab_buat_bill_active.png", height: 25, width: 22),
        ),
        BottomNavigationBarItem(
          label: "Menu 3",
          icon: Image.asset("assets/icon_tab_account.png", height: 25, width: 22),
          activeIcon: Image.asset("assets/icon_tab_account_active.png", height: 25, width: 22),
        ),
      ],
    ),
    tabBuilder: (context, index) 
      if (index == 0) 
        return HomePage(user);
       else if (index == 1) 
        return _bottomSheetMore(context);
      
      return AccountPage(user);
    ),
);


_bottomSheetMore(context) 
showModalBottomSheet(
  context: context,
  builder: (builder) 
    return new Container(
      padding: EdgeInsets.only(
        left: 5.0,
        right: 5.0,
        top: 5.0,
        bottom: 5.0,
      ),
      decoration: new BoxDecoration(
          color: Colors.white,
          borderRadius: new BorderRadius.only(
              topLeft: const Radius.circular(10.0),
              topRight: const Radius.circular(10.0))),
      child: new Wrap(
        children: <Widget>[
          new ListTile(
            title: const Text(
              'Menu Akun',
              style: TextStyle(
                fontSize: 14.0,
                fontWeight: FontWeight.w700,
              ),
            ),
            subtitle: Text("Pilih salah satu"),
          ),
          new Divider(
            height: 10.0,
          ),
          new ListTile(
            title: const Text(
              'Menu Home',
              style: TextStyle(
                fontSize: 14.0,
                fontWeight: FontWeight.w700,
              ),
            ),
          ),
          new Divider(
            height: 10.0,
          ),
          new ListTile(
            title: const Text(
              'Logout',
              style: TextStyle(
                fontSize: 14.0,
                fontWeight: FontWeight.w700,
              ),
            ),
            onTap: () async 
              // Add Here
            ,
          ),
        ],
      ),
    );
  ,
);
 
 

【问题讨论】:

【参考方案1】:

它会显示该错误,因为在显示模态底部表单之前应该先绘制小部件。要显示模态底部表,请在 Future.delayed(...) 中调用它。

你可以试试这样的。

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(home: AppTab()));

class AppTab extends StatefulWidget 
  @override
  _AppTabState createState() => _AppTabState();


class _AppTabState extends State<AppTab> 
  final CupertinoTabController _controller = CupertinoTabController();
  final List<CupertinoPageScaffold> _pages = <CupertinoPageScaffold>[
    CupertinoPageScaffold(
      child: const Center(child: Text('Home Page')),
    ),
    CupertinoPageScaffold(
      child: const Center(child: Text('2nd Page')),
    ),
    CupertinoPageScaffold(
      child: const Center(child: Text('Account Page')),
    ),
  ];

  bool _isBottomSheetShown = false;

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      body: CupertinoTabScaffold(
        controller: _controller,
        tabBar: CupertinoTabBar(
          activeColor: Colors.red,
          inactiveColor: Colors.blue,
          items: const [
            BottomNavigationBarItem(
              label: "Menu 1",
              icon: Icon(Icons.ac_unit),
            ),
            BottomNavigationBarItem(
              label: "Menu 2",
              icon: Icon(Icons.local_activity),
            ),
            BottomNavigationBarItem(
              label: "Menu 3",
              icon: Icon(Icons.assessment),
            ),
          ],
        ),
        tabBuilder: (context, index) 
          return CupertinoTabView(
            builder: (BuildContext context) 
              if (_controller.index == 1 && index == 1) 
                _bottomSheetMore(context);
              

              return _pages[index];
            ,
          );
        ,
      ),
    );
  

  Future<void> _bottomSheetMore(context) async 
    if (_isBottomSheetShown) 
      return;
    

    _isBottomSheetShown = true;

    await Future<void>.delayed(
      const Duration(milliseconds: 10),
      () => showModalBottomSheet<void>(
        context: context,
        builder: (_) 
          return Container(
            height: 300,
            padding: const EdgeInsets.all(5),
            decoration: const BoxDecoration(
              color: Colors.white,
              borderRadius: BorderRadius.only(
                topLeft: const Radius.circular(10.0),
                topRight: const Radius.circular(10.0),
              ),
            ),
            child: Wrap(
              children: <Widget>[
                ListTile(
                  title: const Text(
                    'Menu Akun',
                    style: TextStyle(
                      fontSize: 14.0,
                      fontWeight: FontWeight.w700,
                    ),
                  ),
                  subtitle: const Text("Pilih salah satu"),
                ),
                const Divider(height: 10.0),
                ListTile(
                  title: const Text(
                    'Menu Home',
                    style: TextStyle(
                      fontSize: 14.0,
                      fontWeight: FontWeight.w700,
                    ),
                  ),
                ),
                const Divider(height: 10.0),
                ListTile(
                  title: const Text(
                    'Logout',
                    style: TextStyle(
                      fontSize: 14.0,
                      fontWeight: FontWeight.w700,
                    ),
                  ),
                  onTap: () async 
                    // Add Here
                  ,
                ),
              ],
            ),
          );
        ,
      ),
    );

    _isBottomSheetShown = false;
  

  @override
  void dispose() 
    super.dispose();
    _controller.dispose();
  

【讨论】:

以上是关于在构建 CupertinoTabScaffold 期间调用 setState() 或 markNeedsBuild()的主要内容,如果未能解决你的问题,请参考以下文章

Flutter——WidgetBottomNavigationBar与CupertinoTabScaffold

在 Flutter 中切换时在 CupertinoTabBar 中处理相机预览

使用自动工具构建系统/在单独的“构建”目录中构建

jenkins 构建触发器 以及参数的传递

在构建构建器时,哪一个更有效?

如何在成功发布构建时触发快照构建?