Как использовать BottomNavigationBar с Navigator?

Пример флаттер галереи BottomNavigationBar использует Stack из FadeTransitions в теле Scaffold.

Я чувствую, что было бы чище (и легче анимировать), если бы мы могли переключать страницы с помощью Navigator.

Есть ли примеры этого?

Ответ 1

int index = 0;

@override
Widget build(BuildContext context) {
  return new Scaffold(
    body: new Stack(
      children: <Widget>[
        new Offstage(
          offstage: index != 0,
          child: new TickerMode(
            enabled: index == 0,
            child: new MaterialApp(home: new YourLeftPage()),
          ),
        ),
        new Offstage(
          offstage: index != 1,
          child: new TickerMode(
            enabled: index == 1,
            child: new MaterialApp(home: new YourRightPage()),
          ),
        ),
      ],
    ),
    bottomNavigationBar: new BottomNavigationBar(
      currentIndex: index,
      onTap: (int index) { setState((){ this.index = index; }); },
      items: <BottomNavigationBarItem>[
        new BottomNavigationBarItem(
          icon: new Icon(Icons.home),
          title: new Text("Left"),
        ),
        new BottomNavigationBarItem(
          icon: new Icon(Icons.search),
          title: new Text("Right"),
        ),
      ],
    ),
  );
}

Вы должны хранить каждую страницу Stack чтобы сохранить их состояние. Offstage перестает рисовать, TickerMode останавливает анимацию. MaterialApp включает в себя Navigator.

Ответ 2

Выход:

enter image description here

Код:

int _index = 0;

@override
Widget build(BuildContext context) {
  Widget child;
  switch (_index) {
    case 0:
      child = FlutterLogo();
      break;
    case 1:
      child = FlutterLogo(colors: Colors.orange);
      break;
    case 2:
      child = FlutterLogo(colors: Colors.red);
      break;
  }

  return Scaffold(
    body: SizedBox.expand(child: child),
    bottomNavigationBar: BottomNavigationBar(
      onTap: (newIndex) => setState(() => _index = newIndex),
      currentIndex: _index,
      items: [
        BottomNavigationBarItem(icon: Icon(Icons.looks_one), title: Text("Blue")),
        BottomNavigationBarItem(icon: Icon(Icons.looks_two), title: Text("Orange")),
        BottomNavigationBarItem(icon: Icon(Icons.looks_3), title: Text("Red")),
      ],
    ),
  );
}

Ответ 3

Вот пример:

  int _currentIndex = 0;


  Route<Null> _getRoute(RouteSettings settings) {
    final initialSettings = new RouteSettings(
        name: settings.name,
        isInitialRoute: true);

    return new MaterialPageRoute<Null>(
        settings: initialSettings,
        builder: (context) =>
        new Scaffold(
          body: new Center(
              child: new Container(
                  height: 200.0,
                  width: 200.0,
                  child: new Column(children: <Widget>[
                    new Text(settings.name),
                    new FlatButton(onPressed: () =>
                        Navigator.of(context).pushNamed(
                            "${settings.name}/next"), child: new Text("push")),
                  ],
                  ))
          ),
          bottomNavigationBar: new BottomNavigationBar(
              currentIndex: _currentIndex,
              onTap: (value) {
                final routes = ["/list", "/map"];
                _currentIndex = value;
                Navigator.of(context).pushNamedAndRemoveUntil(
                    routes[value], (route) => false);
              },
              items: [
                new BottomNavigationBarItem(
                    icon: new Icon(Icons.list), title: new Text("List")),
                new BottomNavigationBarItem(
                    icon: new Icon(Icons.map), title: new Text("Map")),
              ]),
        ));
  }

  @override
  Widget build(BuildContext context) =>
      new MaterialApp(
        initialRoute: "/list",
        onGenerateRoute: _getRoute,
        theme: new ThemeData(
          primarySwatch: Colors.blue,
        ),
      );

Вы можете установить isInitialRoute в true и передать его в MaterialPageRoute. Он удалит поп-анимацию.

Чтобы удалить старые маршруты, вы можете использовать pushNamedAndRemoveUntil

Navigator.of(context).pushNamedAndRemoveUntil(routes[value], (route) => false);

Чтобы установить текущую страницу, вы можете иметь переменную в вашем состоянии _currentIndex и назначить ее BottomNavigationBar:

Ответ 4

Вот пример того, как вы можете использовать Navigator с BottomNavigationBar для навигации по другому экрану.

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

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

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

class _MyHomePageState extends State<MyHomePage> {
  // This navigator state will be used to navigate different pages
  final GlobalKey<NavigatorState> _navigatorKey = GlobalKey<NavigatorState>();
  int _currentTabIndex = 0;

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: Navigator(key: _navigatorKey, onGenerateRoute: generateRoute),
        bottomNavigationBar: _bottomNavigationBar(),
      ),
    );
  }

  Widget _bottomNavigationBar() {
    return BottomNavigationBar(
      type: BottomNavigationBarType.fixed,
      items: [
        BottomNavigationBarItem(
          icon: Icon(Icons.home),
          title: Text("Home"),
        ),
        BottomNavigationBarItem(
            icon: Icon(Icons.account_circle), title: Text("Account")),
        BottomNavigationBarItem(
          icon: Icon(Icons.settings),
          title: Text("Settings"),
        )
      ],
      onTap: _onTap,
      currentIndex: _currentTabIndex,
    );
  }

  _onTap(int tabIndex) {
    switch (tabIndex) {
      case 0:
        _navigatorKey.currentState.pushReplacementNamed("Home");
        break;
      case 1:
        _navigatorKey.currentState.pushReplacementNamed("Account");
        break;
      case 2:
        _navigatorKey.currentState.pushReplacementNamed("Settings");
        break;
    }
    setState(() {
      _currentTabIndex = tabIndex;
    });
  }

  Route<dynamic> generateRoute(RouteSettings settings) {
    switch (settings.name) {
      case "Account":
        return MaterialPageRoute(builder: (context) => Container(color: Colors.blue,child: Center(child: Text("Account"))));
      case "Settings":
        return MaterialPageRoute(builder: (context) => Container(color: Colors.green,child: Center(child: Text("Settings"))));
      default:
        return MaterialPageRoute(builder: (context) => Container(color: Colors.white,child: Center(child: Text("Home"))));
    }
  }
}

Ответ 5

Navigator.of(context).pushNamedAndRemoveUntil(
                routes[value], (route) => true);

Мне пришлось использовать true, чтобы включить кнопку назад.

NB: я использовал Navigator.pushNamed() для навигации.