Как программно выбрать вкладку BottomNavigationBar во Flutter вместо встроенного обратного вызова onTap?

Я работал с BottomNavigationBar во флаттере, но я не могу программно выбрать вкладку за пределами обратного вызова onTap для BottomNavigationBar.

Код с обратным вызовом 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.

Я попытался изменить индекс, используемый BottomNavigatioBar вне onTap callBack, но это не сработало.

Вот что я пробовал:

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

Вот суть кода.

Есть ли способ изменить вкладки?


person Harsh Sharma    schedule 21.06.2018    source источник
comment
Не могли бы вы предоставить весь код вашего класса?   -  person Javid Noutash    schedule 21.06.2018
comment
@JavidNoutash подождите, я публикую   -  person Harsh Sharma    schedule 21.06.2018
comment
Суть @JavidNoutash для добавленного кода   -  person Harsh Sharma    schedule 21.06.2018
comment
Ваш код немного запутан, есть немного дублирования логики, поэтому вы немного растерялись. Всякий раз, когда вы хотите обновить вкладку панели навигации: setState((){ apiHomeWidget = YOUR_TAB_PAGE; navigationIndex = YOUR_TAB_INDEX; });   -  person Javid Noutash    schedule 21.06.2018
comment
я уже пробовал ту вещь, о которой вы уже упоминали в методе handleBottomNavigationBarClicks, но она не работает   -  person Harsh Sharma    schedule 21.06.2018
comment
@JavidNoutash, можете ли вы поделиться кодом, если он работает на вас?   -  person Harsh Sharma    schedule 21.06.2018


Ответы (4)


Вот полный пример того, как достичь того, чего вы хотите.

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)

person Javid Noutash    schedule 21.06.2018
comment
Есть ли способ изменить вкладку от ребенка? Если у меня есть кнопка на странице 1 и при ее нажатии я хочу перейти на вторую вкладку (страница 2) - person HardikDG; 22.08.2019
comment
@HardikDG, вы можете использовать метод обратного вызова для динамического изменения нижней панели навигации из дочернего элемента. - person Atul Chaudhary; 15.07.2020

Вы можете получить этот виджет BottomNavigationBar с помощью GlobalKey. С помощью этого GlobalKey вы можете управлять этим виджетом. Вот суть кода

Здесь вы назначаете GlobalKey

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

И поместите этот ключ в свой BottomNavigationBar

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

Теперь вы можете вызвать метод виджета и использовать CurvedNavigationBar вместо BottomNavigationBar, если вам нужно работать с CurvedNavigationBar.

 final BottomNavigationBar navigationBar = globalKey.currentWidget;
 navigationBar.onTap(2);
person Huy Hoàng    schedule 21.06.2018
comment
Спасибо за ваш ответ, постараюсь сообщить вам, работает ли он, и отметит ваш ответ как принятый. - person Harsh Sharma; 21.06.2018
comment
Искал ВСЁ, пытаясь найти это. Как раз собирался опубликовать тот же вопрос, когда наконец нашел это. Судя по этому вступительному видео по Flutter, это кажется лучшим способом: youtube. com/watch?v=kn0EOS-ZiIc - person Eric Duffett; 20.02.2019
comment
Разве это не функция отладки? - person Rony Tesler; 03.03.2021

Спасибо от @HuyHoàng за флаттер версии 2+. Я использую это:

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

затем назначьте эту клавишу для BottomNavigationBar, после чего вы сможете получить доступ к нижней части, как показано ниже:

BottomNavigationBar navigationBar =  bottomWidgetKey.currentWidget as BottomNavigationBar;
navigationBar.onTap!(1);
person Shojaeddin    schedule 03.08.2021

Еще одно обходное решение для 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'),),));
  }
}
person Max    schedule 12.06.2021