Flutter BottomNavigationBar仅更改屏幕,但不更改选择

gcuhipw9  于 2023-01-14  发布在  Flutter
关注(0)|答案(2)|浏览(142)

大家好,我是Flutter的新手,我正在尝试将BottomNavigationBar添加到我的应用程序中,但是我在标题中遇到了一个问题。
正如您在下面看到的,我将currentIndex的状态和一个在不同类中点击时调用的方法放置在其中。
page_frame.dart(它具有状态和方法)

// ...

class PageFrame extends StatefulWidget {
  const PageFrame({super.key});

  @override
  State<PageFrame> createState() => _PageFrameState();
}

class _PageFrameState extends State<PageFrame> {
  int _currentPageIndex = 0;

  final List<Widget> _pages = <Widget>[
    const Home(),
    const Announcement()
  ];

  void _onPageTap(int index) {
    setState(() {
      _currentPageIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor     : const Color(0xFF183977),
      body                : _pages.elementAt(_currentPageIndex),
      bottomNavigationBar : SPBottomNavigationBar(
        currentIndex : _currentPageIndex,
        onTap        : _onPageTap
      ),
    );
  }
}

my_bottom_navigation_var.dart(从上面接收状态和方法)

// ...

class MyBottomNavigationBar extends StatefulWidget {
  final int currentIndex;
  final ValueChanged<int> onTap;
  const MyBottomNavigationBar({required this.currentIndex, required this.onTap, Key? key})
    : super(key: key);

  @override
  State<MyBottomNavigationBar> createState() => _MyBottomNavigationBarState();
}

class _MyBottomNavigationBarState extends State<MyBottomNavigationBar> {
  late int currentIndex;
  late ValueChanged<int> onTap;

  @override
  void initState() {
    super.initState();
    currentIndex = widget.currentIndex;
    onTap        = widget.onTap;
  }

  @override
  Widget build(BuildContext context) {
    return BottomNavigationBar(
      unselectedItemColor : const Color(0xFFFFFFFF),
      selectedItemColor   : const Color(0xFF008BF1),
      showUnselectedLabels: true,
      items               : const [
        BottomNavigationBarItem(
          icon            : Icon(Icons.home),
          label           : 'Home',
          backgroundColor : Color(0xFF000000)
        ),
        BottomNavigationBarItem(
          icon            : Icon(Icons.announcement),
          label           : 'Announcement',
          backgroundColor : Color(0xFF000000)
        )
      ],
      currentIndex : currentIndex,
      onTap        : onTap,
    );
  }
}

这导致如果我点击公告图标,只有屏幕从主页变为公告,但所选图标仍然是主页,如下所示:Screen : Home, Selection : HomeScreen : Announcement, Selection : Home我认为这可能是因为缺乏交互性,即使是这样,我也不知道如何获得这种交互性。请告诉我该怎么做。谢谢。

igetnqfo

igetnqfo1#

您的MyBottomNavigationBar状态类有其生命周期,它在initState上第一次获得currentIndex值。您可以使用直接访问widget类变量

widget.variableName

您可以使用like

class MyBottomNavigationBar extends StatefulWidget {
  final int currentIndex;
  final ValueChanged<int> onTap;
  const MyBottomNavigationBar(
      {required this.currentIndex, required this.onTap, Key? key})
      : super(key: key);

  @override
  State<MyBottomNavigationBar> createState() => _MyBottomNavigationBarState();
}

class _MyBottomNavigationBarState extends State<MyBottomNavigationBar> {
  @override
  Widget build(BuildContext context) {
    return BottomNavigationBar(
      unselectedItemColor: const Color(0xFFFFFFFF),
      selectedItemColor: const Color(0xFF008BF1),
      showUnselectedLabels: true,
      items: const [
        BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: 'Home',
            backgroundColor: Color(0xFF000000)),
        BottomNavigationBarItem(
            icon: Icon(Icons.announcement),
            label: 'Announcement',
            backgroundColor: Color(0xFF000000))
      ],
      currentIndex: widget.currentIndex,
      onTap: widget.onTap,
    );
  }
}

你也可以在这里使用无状态小部件,父(home)小部件在索引改变时传递新值,这个小部件会自动重建。

class MyBottomNavigationBar extends StatelessWidget {
  final int currentIndex;
  final ValueChanged<int> onTap;
  const MyBottomNavigationBar(
      {required this.currentIndex, required this.onTap, Key? key})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return BottomNavigationBar(
      unselectedItemColor: const Color(0xFFFFFFFF),
      selectedItemColor: const Color(0xFF008BF1),
      showUnselectedLabels: true,
      items: const [
        BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: 'Home',
            backgroundColor: Color(0xFF000000)),
        BottomNavigationBarItem(
            icon: Icon(Icons.announcement),
            label: 'Announcement',
            backgroundColor: Color(0xFF000000))
      ],
      currentIndex: currentIndex,
      onTap: onTap,
    );
  }
}
cpjpxq1n

cpjpxq1n2#

您的主屏幕正在更新,而NavigationBar没有更新的原因很简单,因为它们有两个“不同”的状态。
在主屏幕中,有一个变量,包含当前页面索引,当用户点击NavigationBar时,更新该变量并重绘小部件,但不会重绘子小部件,因为子小部件的状态没有改变。
有两个简单的解决方法。

导航栏作为无状态小部件

由于导航栏从来不使用它的状态,你可以将它转换成StatelessWidget,并在构造函数中传递活动索引,这样,当主屏幕改变时,它会用新的索引重建NavigationBar

class MyBottomNavigationBar extends StatelessWidget {
  final int currentIndex;
  final ValueChanged<int> onTap;
  const MyBottomNavigationBar(
      {Key? key, required this.currentIndex, required this.onTap})
      : super(key: key);
  // ...

导航栏作为状态小部件

另一种解决方法是将NavigationBar保留为StatefulWidget,但当用户点击时,您会更新此处的状态,并传递选定的索引。只需按以下方式更改onTap()
您将写入以下内容,而不是onTap: onTap

onTap: (index) {
  setState((){
    currentIndex = index;
  });
  widget.onTap(index);
}

如您所见,您甚至不需要为initState()中的回调函数创建状态变量,只需在此处调用它即可。

相关问题