更改徽章编号

Posted

技术标签:

【中文标题】更改徽章编号【英文标题】:Change badge number 【发布时间】:2020-01-11 18:15:49 【问题描述】:

在 MainPage 中,它有 2 个底部导航栏。一个是带有文字的图标,另一个是带有文字和徽章编号的图标。当我的应用程序启动时,徽章在第二个选项卡中显示为 3。这很好用。

  class MainPage extends StatefulWidget 

  @override
  State<StatefulWidget> createState() 
    return _MainPageState();
  

  method(int num) => _MainPageState().showBadge(num);


class _MainPageState extends State<MainPage>
    with SingleTickerProviderStateMixin 
  int _selectedIndex = 0;
  int count = 0;
  TabController _tabController;
  PageController _pageController;

  @override
  void initState() 
    super.initState();

    _tabController = TabController(length: 5, vsync: this);
    _pageController = PageController(initialPage: _selectedIndex);

    showBadge(3);
  

  void showBadge(int number) 
    setState(() 
      count = number;
    );
  

  void onPageChange(int index) 
    setState(() 
      _selectedIndex = index;
    );
  

  void _onItemTapped(int index) 
    _pageController.animateToPage(index,
        duration: kTabScrollDuration, curve: Curves.ease);
  

  @override
  Widget build(BuildContext context) 
    return WillPopScope(
      child: Scaffold(
        body: FixTabBarView(
            pageController: _pageController,
            onPageChange: onPageChange,
            tabController: _tabController,
            children: <Widget>[
              TabA(),
              TabB(),
            ]),
        bottomNavigationBar: BottomNavigationBar(
          type: BottomNavigationBarType.fixed,
          items: <BottomNavigationBarItem>[
            BottomNavigationBarItem(
                icon: Icon(Icons.A), title: Text('TabA')),
            BottomNavigationBarItem(
              icon: Stack(children: <Widget>[
                Icon(
                  Icons.B,
                ),
                Positioned(
                  top: 1.0,
                  right: 0.0,
                  child: Stack(
                    children: <Widget>[
                      Icon(Icons.brightness_1, size: 18, color: Colors.red),
                      Positioned(
                        top: 1.0,
                        right: 4.0,
                        child: new Text(count.toString(),
                            style: new TextStyle(
                                color: Colors.white,
                                fontSize: 15.0,
                                fontWeight: FontWeight.w500)),
                      )
                    ],
                  ),
                )
              ]),
              title: Text('TabB'),
            ),
          ],
          currentIndex: _selectedIndex,
          fixedColor: Colors.blue,
          onTap: _onItemTapped,
        ),
      ),
      onWillPop: () ,
    );
  

当点击标签 2 时,我希望徽章更改为 1,但它会引发错误。

  class TabB extends StatefulWidget 

  @override
  State<StatefulWidget> createState() => _TabBState();


class _TabBState extends State<TabB> 

  @override
  void initState() 
    super.initState();
    _bloc.callApi().then((onValue)
      MainPage().method(onValue);    // onValue is the number return from server
  );
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
        appBar: AppBar(
      title: Text("Tab 2"),
    ));
  

错误

════════ 小部件库捕获的异常 ═══════════════════════════════════抛出以下断言 构建通知监听器:setState() 在构造函数中调用:_MainPageState#6ed53(生命周期状态:已创建, 没有小部件,没有安装)

当您在小部件的 State 对象上调用 setState() 时会发生这种情况 尚未插入到小部件树中。它不是 必须在构造函数中调用 setState(),因为状态是 在最初创建时已经假定它是脏的。

【问题讨论】:

【参考方案1】:

在加载子窗口小部件时,不要尝试从父窗口小部件调用函数来修改徽章,而应向 _tabController 添加监听器并在选择选项卡时更改徽章,如下所示:

@override
void initState() 
  super.initState();

  _tabController = TabController(length: 5, vsync: this);
  _tabController.addListener(()
    if(_tabController.index == 1)
      setState(() 
        showBadge(1);
      );
    
  );

  _pageController = PageController(initialPage: _selectedIndex);

  showBadge(3);

确保为要匹配的标签索引调整if


在您的TabB 上,您可以声明它接受Function 作为其构造函数的一部分,然后调用该函数:

class TabB extends StatefulWidget 
  final Function showBadge;

  TabB(this.showBadge);

  @override
  State<StatefulWidget> createState() => _TabBState();


class _TabBState extends State<TabB> 

  @override
  void initState() 
    super.initState();
    _bloc.callApi().then((onValue)
      widget.showBadge(onValue);    // onValue is the number return from server
    );
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        title: Text("Tab 2"),
      )
    );
  

在您的主小部件上:

FixTabBarView(
  pageController: _pageController,
  onPageChange: onPageChange,
  tabController: _tabController,
  children: <Widget>[
    TabA(),
    TabB(showBadge: showBadge,),
  ]
)

【讨论】:

看起来我必须先从 PageB 调用 MainPage 中的 Widget 构建,然后再调用 setState 请检查我对回复的更改。你不需要让你的代码变得这么复杂。有更简单的方法可以监听选项卡上的变化。 您好,感谢您的回答。但在实际情况下,出于某种原因,我需要在选项卡 2 initState 中调用一个 api。该数字应该从 tabB 返回到 tabA。 您不需要调用父 Widget 的整个实例来调用其中一个方法。您可以将方法向下传递给子 Widget。我会将其添加到响应中。 请检查我添加到回复中的额外解释和代码。如果它对您有所帮助并解决了您的问题。确保将其标记为正确。

以上是关于更改徽章编号的主要内容,如果未能解决你的问题,请参考以下文章

iOS 8. 在没有任何通知的情况下更改应用徽章编号

如何重置徽章应用图标编号?

ios5中的应用程序图标徽章编号

更新 iOS 图标徽章编号

如果我没有启用徽章,为啥我的 iOS 应用程序图标会显示徽章编号?

Expo - 实施通知设置应用程序图标徽章编号