如何在Flutter中以编程方式选择BottomNavigationBar Tab而不是内置在onTap回调中?

ubby3x7f  于 2023-08-07  发布在  Flutter
关注(0)|答案(7)|浏览(110)

我一直在使用Flutter中的BottomNavigationBar,但我无法在BottomNavigationBar的onTap回调之外以编程方式选择Tab。
使用onTap回调的代码,它正在工作:

return new BottomNavigationBar(
  items: <BottomNavigationBarItem>[
    _bottomNavigationItem(Icons.account_circle, DrawerTitles.CONTACTS),
    _bottomNavigationItem(Icons.delete, DrawerTitles.DELETED_CONTACTS),
    _bottomNavigationItem(Icons.list, DrawerTitles.LOGS),
  ],
  onTap: (int index) {
    setState(() {
      navigationIndex = index;
      switch (navigationIndex) {
        case 0:
          handleBottomNavigationBarClicks(DrawerTitles.CONTACTS);
          break;
        case 1:
          handleBottomNavigationBarClicks(DrawerTitles.DELETED_CONTACTS);
          break;
        case 2:
          handleBottomNavigationBarClicks(DrawerTitles.LOGS);
          break;
      }
    });
  },
  currentIndex: navigationIndex,
  fixedColor: Colors.blue[400],
  type: BottomNavigationBarType.fixed,
);

字符串
但我想更改onTap回调之外的选项卡。
我尝试在onTap回调之外更改BottomNavigatioBar使用的索引,但没有成功。
以下是我尝试过的:

void changeTabs(int tabIndex) {
setState(() {
     navigationIndex = tabIndex;
});}


下面是一个gist的代码。
有没有什么方法可以改变标签?

7d7tgy0s

7d7tgy0s1#

您可以通过使用GlobalKey获取这个BottomNavigationBar小部件。通过此GlobalKey,您可以处理此小部件。Here is an gist for the code
在这里分配一个GlobalKey

GlobalKey globalKey = new GlobalKey(debugLabel: 'btm_app_bar');

字符串
然后把钥匙放到你的底部导航栏

new BottomNavigationBar(
    key: globalKey,
    items: [...],
   onTap: (int index) {...},
  ),


现在,如果必须使用CurvedNavigationBar,您可以调用widget的方法并使用CurvedNavigationBar而不是BottomNavigationBar。

final BottomNavigationBar navigationBar = globalKey.currentWidget;
 navigationBar.onTap(2);

vvppvyoh

vvppvyoh2#

这里有一个完整的例子,说明如何实现你想要的东西。

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

const String page1 = "Page 1";
const String page2 = "Page 2";
const String page3 = "Page 3";
const String title = "BNB Demo";

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: title,
      home: new MyHomePage(title: title),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  List<Widget> _pages;
  Widget _page1;
  Widget _page2;
  Widget _page3;

  int _currentIndex;
  Widget _currentPage;

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

    _page1 = Page1();
    _page2 = Page2();
    _page3 = Page3();

    _pages = [_page1, _page2, _page3];

    _currentIndex = 0;
    _currentPage = _page1;
  }

  void changeTab(int index) {
    setState(() {
      _currentIndex = index;
      _currentPage = _pages[index];
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: _currentPage,
      bottomNavigationBar: BottomNavigationBar(
          onTap: (index) => changeTab(index),
          currentIndex: _currentIndex,
          items: [
            BottomNavigationBarItem(
                title: Text(page1), icon: Icon(Icons.account_circle)),
            BottomNavigationBarItem(
                title: Text(page2), icon: Icon(Icons.account_circle)),
            BottomNavigationBarItem(
                title: Text(page3), icon: Icon(Icons.account_circle))
          ]),
      drawer: new Drawer(
        child: new Container(
          margin: EdgeInsets.only(top: 20.0),
          child: new Column(
            children: <Widget>[
              navigationItemListTitle(page1, 0),
              navigationItemListTitle(page2, 1),
              navigationItemListTitle(page3, 2),
            ],
          ),
        ),
      ),
    );
  }

  Widget navigationItemListTitle(String title, int index) {
    return new ListTile(
      title: new Text(
        title,
        style: new TextStyle(color: Colors.blue[400], fontSize: 22.0),
      ),
      onTap: () {
        Navigator.pop(context);
        changeTab(index);
      },
    );
  }
}

class Page1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text(page1),
    );
  }
}

class Page2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text(page2),
    );
  }
}

class Page3 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text(page3),
    );
  }
}

字符串
每当你想改变一个标签,调用changeTab(YOUR_TAB_INDEX)

czfnxgou

czfnxgou3#

谢谢你从@HuyHoàng为flutter版本2+我使用这个:

var bottomWidgetKey=new GlobalKey<State<BottomNavigationBar>>();

字符串
然后将此键分配给BottomNavigationBar,然后可以访问底部,如下所示:

BottomNavigationBar navigationBar =  bottomWidgetKey.currentWidget as BottomNavigationBar;
navigationBar.onTap!(1);

wvyml7n5

wvyml7n54#

下面是回答上述第一个问题的完整示例。代码是从上面修改的。注意回调方法传递给第3页构造函数。

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

const String page1 = "Home";
const String page2 = "Service";
const String page3 = "Profile";
const String title = "BNB Demo";

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: title,
      home: MyHomePage(title: title),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late List<Widget> _pages;
  late Widget _page1;
  late Widget _page2;
  late Widget _page3;
  late int _currentIndex;
  late Widget _currentPage;

  @override
  void initState() {
    super.initState();
    _page1 = const Page1();
    _page2 = const Page2();
    _page3 = Page3(changePage: _changeTab);
    _pages = [_page1, _page2, _page3];
    _currentIndex = 0;
    _currentPage = _page1;
  }

  void _changeTab(int index) {
    setState(() {
      _currentIndex = index;
      _currentPage = _pages[index];
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: _currentPage,
      bottomNavigationBar: BottomNavigationBar(
          onTap: (index) {
            _changeTab(index);
          },
          currentIndex: _currentIndex,
          items: const [
            BottomNavigationBarItem(
              label: page1,
              icon: Icon(Icons.home),
            ),
            BottomNavigationBarItem(
              label: page2,
              icon: Icon(Icons.home_repair_service),
            ),
            BottomNavigationBarItem(
              label: page3,
              icon: Icon(Icons.person),
            ),
          ]),
      drawer: Drawer(
        child: Container(
          margin: const EdgeInsets.only(top: 20.0),
          child: Column(
            children: <Widget>[
              _navigationItemListTitle(page1, 0),
              _navigationItemListTitle(page2, 1),
              _navigationItemListTitle(page3, 2),
            ],
          ),
        ),
      ),
    );
  }

  Widget _navigationItemListTitle(String title, int index) {
    return ListTile(
      title: Text(
        '$title Page',
        style: TextStyle(color: Colors.blue[400], fontSize: 22.0),
      ),
      onTap: () {
        Navigator.pop(context);
        _changeTab(index);
      },
    );
  }
}

class Page1 extends StatelessWidget {
  const Page1({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text('$page1 Page', style: Theme.of(context).textTheme.headline6),
    );
  }
}

class Page2 extends StatelessWidget {
  const Page2({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text('$page2 Page', style: Theme.of(context).textTheme.headline6),
    );
  }
}

class Page3 extends StatelessWidget {
  const Page3({Key? key, required this.changePage}) : super(key: key);
  final void Function(int) changePage;

  @override
  Widget build(BuildContext context) {
    return Align(
      alignment: Alignment.center,
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Text('$page3 Page', style: Theme.of(context).textTheme.headline6),
          ElevatedButton(
            onPressed: () => changePage(0),
            child: const Text('Switch to Home Page'),
          )
        ],
      ),
    );
  }
}

字符串

ua4mk5z4

ua4mk5z45#

如果你想从一个小部件中更改标签,你可以这样做:
假设这是您要更改当前活动选项卡的小部件:

class MyWidget extends StatefulWidget {

  final Function() openHomeTab;

  MyWidget({
    this.openHomeTab,
  });
  @override
  _MyWidget createState() => _MyWidget();
}

class _MyWidget extends State<MyWidget> {
  @override
  Widget build(BuildContext context) {
    return CupertinoButton(
      onPressed: () {
        widget.openHomeTab();
      },
    );
  }
}

字符串
现在,在包含标签栏的小部件(BottomNavigationBar)中:

@override
  Widget build(BuildContext context) {
    return Scaffold(
      body: IndexedStack(
        index: _currentTab,
        children: _buildScreens(),
      ),
      bottomNavigationBar: BottomNavigationBar(
        showSelectedLabels: true,
        showUnselectedLabels: true,
        selectedItemColor: Colors.primary,
        //selectedLabelStyle: TextStyle(),
        elevation: 0,
        type: BottomNavigationBarType.fixed,
        onTap: (index) {
          openTab(index);
        },
        currentIndex: _currentTab,
        items: <BottomNavigationBarItem>[
          _buildTabIcon(0),
          _buildTabIcon(1),
          _buildTabIcon(2),
          _buildTabIcon(3),
          _buildTabIcon(4)
        ],
      ),
    );
  }

 
  List<StatefulWidget> _buildScreens() {
    _screens = <StatefulWidget>[
      ..., 
      ...,
      ...,
      MyWidget(
        openHomeTab: openHomeTab,
      )
    ];
    return _screens;
  }

  void openHomeTab() {
    openTab(0);
  }

  void openTab(int index) {
    setState(() {
      _currentTab = index;
    });
  }

ttp71kqs

ttp71kqs6#

如果有人有同样的问题,我的不仅仅是得到下一个标签,但也允许切换动画。

GlobalKey _bottomNavigationKey = GlobalKey();

字符串
曲线导航栏

bottomNavigationBar: CurvedNavigationBar(
      key: _bottomNavigationKey,
      items: <Widget>[
        Icon(Icons.add, size: 25),
        Icon(Icons.abc, size: 25),
        Icon(Icons.home, size: 25),
      ],
      onTap: (index) {
        setState(() {
          _page = index;
        });
      },
    ),


那么在你的代码中

RaisedButton(
   child: Text('Animate to Page 0'),
    onPressed: () {
     //Page change using state does the same as clicking index 0 navigation button

     final dynamic navBarState = _bottomNavigationKey.currentState;
     // Remember to use 'dynamic', instead of 'CurvedNavigationBarState'

     navBarState.setPage(0);
   },
 )

u91tlkcl

u91tlkcl7#

另一个工作解决方案在这里为CupertinoApp。它正在为我的应用程序要求工作。
这也是回答“有没有办法改变标签从孩子?“,因为我们可以在任何子节点中传递控制器,并且我们可以更改选项卡索引。

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

void main() {
  runApp(CupertinoApp(home: HomeScreen(),));
}

final GlobalKey<NavigatorState> firstTabNavKey = GlobalKey<NavigatorState>();
final GlobalKey<NavigatorState> secondTabNavKey = GlobalKey<NavigatorState>();
final GlobalKey<NavigatorState> thirdTabNavKey = GlobalKey<NavigatorState>();

class HomeScreen extends StatelessWidget {

  var controller = CupertinoTabController(initialIndex: 0);

  @override
  Widget build(BuildContext context) {
    return CupertinoTabScaffold(
        controller: controller,
        tabBar: CupertinoTabBar(
          items: <BottomNavigationBarItem>[
            BottomNavigationBarItem(icon: Icon(CupertinoIcons.home)),
            BottomNavigationBarItem(icon: Icon(CupertinoIcons.cart)),
            BottomNavigationBarItem(icon: Icon(CupertinoIcons.person)),
          ],
        ),
        tabBuilder: (context, index) {
          if (index == 0) {
            return CupertinoTabView(navigatorKey: firstTabNavKey, builder: (context) => FirstTab(controller: this.controller,),);
          } else if (index == 1) {
            return CupertinoTabView(navigatorKey: secondTabNavKey, builder: (context) => SecondTab(),);
          } else {
            return CupertinoTabView(navigatorKey: thirdTabNavKey, builder: (context) => ThirdTab(),);
          }
        }
    );
  }
}

class FirstTab extends StatelessWidget {
  final CupertinoTabController controller;

  FirstTab({required this.controller});

  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold( child: Container(
      child: Center(
        child: Row(
          children: <Widget>[
            TextButton(onPressed: () => {controller.index = 1}, child: Text('Second Tab')),
            TextButton(onPressed: () => {controller.index = 2}, child: Text('Third Tab')),
          ],
        ),
      ),
    ));
  }
}

class SecondTab extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold( child:Container(child: Center( child: Text('Second Screen'),),));
  }
}

class ThirdTab extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold( child:Container(child: Center( child: Text('Third Screen'),),));
  }
}

字符串

相关问题