推到新屏幕时,使底部导航栏保持静态

ben*_*est 5 dart flutter

我是一个飞镖和飞镖的初学者。我一直在尝试navigationBar在我的应用程序的三个不同页面上实现。对于单个页面,切换效果很好,但是我在将所有页面上的活动和非活动标签状态保持不变时遇到问题。似乎当它导航到另一个页面时,我也失去了选项卡的活动状态。这是我的代码。

AppFooter.dart

import 'package:flutter/material.dart';

class AppFooter extends StatefulWidget {
  @override
  _AppFooterState createState() => _AppFooterState();
}

class _AppFooterState extends State<AppFooter> {
  int index = 0;
  @override
  Widget build(BuildContext context) {
    return new Theme(
      data: Theme.of(context).copyWith(
          // sets the background color of the `BottomNavigationBar`
          canvasColor: Colors.white,
          // sets the active color of the `BottomNavigationBar` if `Brightness` is light
          primaryColor: Colors.green,
          textTheme: Theme.of(context)
              .textTheme
              .copyWith(caption: new TextStyle(color: Colors.grey))),
      child: new BottomNavigationBar(
          type: BottomNavigationBarType.fixed,
          currentIndex: index,
          onTap: (int index) {
            setState(() {
              this.index = index;
            });
          switch (index){
            case 0:  Navigator.of(context).pushNamed('/dashboard');
            break;
            case 1:  Navigator.of(context).pushNamed('/medical centre');
            break;
            case 2:  Navigator.of(context).pushNamed('/history');
            break;

          }

          },
          items: [
            new BottomNavigationBarItem(
                backgroundColor: Colors.white,
                icon: index==0?new Image.asset('assets/images/dashboard_active.png'):new Image.asset('assets/images/dashboard_inactive.png'),
                title: new Text('Dashboard', style: new TextStyle(fontSize: 12.0))),
           new BottomNavigationBarItem(
               backgroundColor: Colors.white,
               icon: index==1?new Image.asset('assets/images/medical_sevice_active.png'):new Image.asset('assets/images/medical_sevice_inactive.png'),
               title: new Text('Health Services', style: new TextStyle(fontSize: 12.0))),
            new BottomNavigationBarItem(
                icon: InkWell(
                  child: Icon(
                    Icons.format_align_left,
                   // color: green,
                    size: 20.0,
                  ),
                ),
                title: new Text('History', style: new TextStyle(fontSize: 12.0))),
          ]),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

Abi*_*bin 21

如果我正确理解您的问题,您需要在所有三个页面上都保留底部导航栏。有一篇写得很好的文章介绍了如何实现它。您可以在此处找到详细信息。

https://medium.com/coding-with-flutter/flutter-case-study-multiple-navigators-with-bottomnavigationbar-90eb6caa6dbf

https://github.com/bizz84/nested-navigation-demo-flutter

所有学分归原作者所有。

  • 我尝试了上述方法,发现最大的问题是,当我们更改 1 个选项卡时,它将触发其他选项卡的构建方法,我认为这对性能非常不利。只需在其他选项卡的构建方法中添加日志行,您就会看到每次更改选项卡时都会调用日志行。 (2认同)

Mai*_*ais 8

使用PageViewbottomNavigationBar

import 'package:flutter/material.dart';

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

/// This Widget is the main application widget.
class MyApp extends StatelessWidget {
  static const String _title = 'Flutter App';

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

class App extends StatefulWidget {
  App({Key key}) : super(key: key);
  _AppState createState() => _AppState();
}

class _AppState extends State<App> {
  PageController _myPage;
  var selectedPage;

  @override
  void initState() {
    super.initState();
    _myPage = PageController(initialPage: 1);
    selectedPage = 1;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: PageView(
          physics: NeverScrollableScrollPhysics(),
          controller: _myPage,
          children: <Widget>[
            Center(
              child: Text("Another Page"),
            ),
            Center(
                child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text("Page 1"),
                RaisedButton(
                  onPressed: () {
                    _myPage.jumpToPage(0);
                    setState(() {
                      selectedPage = 0;
                    });
                  },
                  child: Text("Go to another page"),
                )
              ],
            )),
            Center(child: Text("Page 2")),
            Center(child: Text("Page 3")),
          ],
        ),
        bottomNavigationBar: BottomAppBar(
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: <Widget>[
              IconButton(
                icon: Icon(Icons.home),
                color: selectedPage == 1 ? Colors.blue : Colors.grey,
                onPressed: () {
                  _myPage.jumpToPage(1);
                  setState(() {
                    selectedPage = 1;
                  });
                },
              ),
              IconButton(
                icon: Icon(Icons.star),
                color: selectedPage == 2 ? Colors.blue : Colors.grey,
                onPressed: () {
                  _myPage.jumpToPage(2);
                  setState(() {
                    selectedPage = 2;
                  });
                },
              ),
              IconButton(
                icon: Icon(
                  Icons.settings,
                ),
                color: selectedPage == 3 ? Colors.blue : Colors.grey,
                onPressed: () {
                  _myPage.jumpToPage(3);
                  setState(() {
                    selectedPage = 3;
                  });
                },
              ),
            ],
          ),
        ));
  }
}
Run Code Online (Sandbox Code Playgroud)

此外,如果您想保留页面之间的状态,以便转到另一个页面不会导致前一个页面丢失其状态,请使用AutomaticKeepAliveClientMixin

此外,延迟加载页面PageView.builder是另一种解决方案。

希望能帮助到你。

  • 如果我正确地回答了问题,那么一旦在页面之间移动,他就会丢失状态,理想情况下,我希望在页面之间保留状态,这就是为什么使用 PageView 是一个简单的解决方案。只需使用“AutomaticKeepAliveClientMixin”在某些或所有页面中实现此目的就很容易。https://api.flutter.dev/flutter/widgets/AutomaticKeepAliveClientMixin-mixin.html 另外,如果你想延迟加载页面,使用 PageView.builder 也可以实现这一点。 (3认同)

Mat*_*ias 6

另一个很好的解决方案是Bilal Shahid提供的persistent_bottom_nav_bar包。

它易于使用并为您提供了一系列功能

  • 高度可定制的持久底部导航栏。
  • 能够在有或没有底部导航栏的情况下推送新屏幕。
  • 底部导航栏的 20 种样式。
  • 包括使用或不使用底部导航栏推送屏幕的功能,即 pushNewScreen() 和 pushNewScreenWithRouteSettings()。
  • 基于 flutter 的 Cupertino(iOS) 底部导航栏。
  • 对于特定选项卡可以是半透明的。
  • 导航栏的自定义样式。点击这里查看更多信息。处理硬件/软件 Android 后退按钮。

在我找到这个包之前,我遵循了@Abin 在他的回答中提到的文章中的解决方案。但是我遇到了这个问题,这一切都screens来自navbar第一次加载的蜜蜂,navbar这不是那么性能。我没有解决这个问题,但幸运的是Bilal Shahid用他的包提供了一个很好的解决方案。

所有功劳都归功于他。


Hus*_*ish 6

只需复制并过去:)

主要.dart:

void main() async{
  runApp(MyGrillApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(

      routes: {
        '/mainlayout': (context) => MainLayout(),
        '/page1': (context) => Page1(),
        '/page2': (context) => Page2(),
        '/page3': (context) => Page3(),
        '/page4': (context) => Page4(),
      },
      initialRoute: '/mainlayout',
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

main_layout.dart:

class MainLayout extends StatefulWidget {
  @override
  _MainLayoutState createState() => _MainLayoutState();
}

class _MainLayoutState extends State<MainLayout> {
  int _currentIndex = 0;

  final _page1 = GlobalKey<NavigatorState>();
  final _page2 = GlobalKey<NavigatorState>();
  final _page3 = GlobalKey<NavigatorState>();
  final _page4 = GlobalKey<NavigatorState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButtonLocation: FloatingActionButtonLocation.miniCenterDocked,
      floatingActionButton: Padding(
        padding: const EdgeInsets.all(6.0),
        child: FloatingActionButton(
          backgroundColor: Colors.redAccent,
          child: const Icon(Icons.add, color: Colors.white),
          onPressed: () {
            // ToDo...
          },
        ),
      ),
      body: IndexedStack(
        index: _currentIndex,
        children: <Widget>[
          Navigator(
            key: _page1,
            onGenerateRoute: (route) => MaterialPageRoute(
              settings: route,
              builder: (context) => Page1(),
            ),
          ),
          Navigator(
            key: _page2,
            onGenerateRoute: (route) => MaterialPageRoute(
              settings: route,
              builder: (context) => Page2(),
            ),
          ),
          Navigator(
            key: _page3,
            onGenerateRoute: (route) => MaterialPageRoute(
              settings: route,
              builder: (context) => Page3(),
            ),
          ),
          Navigator(
            key: _page4,
            onGenerateRoute: (route) => MaterialPageRoute(
              settings: route,
              builder: (context) => Page4(),
            ),
          ),
        ],
      ),
      bottomNavigationBar: BottomAppBar(
        shape: const CircularNotchedRectangle(),
        clipBehavior: Clip.antiAlias,
        child: BottomNavigationBar(
          backgroundColor: Colors.white,
          currentIndex: _currentIndex,
          onTap: (index) {
            setState(() {
              _currentIndex = index;
            });
          },
          type: BottomNavigationBarType.fixed,
          selectedItemColor: Colors.redAccent,
          unselectedItemColor: Colors.grey,
          showSelectedLabels: false,
          showUnselectedLabels: false,
          items: const <BottomNavigationBarItem>[
            BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
            BottomNavigationBarItem(icon: Icon(Icons.date_range), label: 'Statistics'),
            BottomNavigationBarItem(icon: Icon(Icons.wallet_giftcard), label: 'Wallet'),
            BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'),
          ],
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

详细信息屏幕:

class ItemDetailsPage extends StatefulWidget {
  const ItemDetailsPage({Key? key}) : super(key: key);

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

class _ItemDetailsPageState extends State<ItemDetailsPage> with AutomaticKeepAliveClientMixin{
  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Scaffold(
        appBar: AppBar(
          backgroundColor: themeColorPrimary,
          title: Text('Item details',),
        ),
        body : Container(child: Text('Hello from details'),));
  }

  @override
  bool get wantKeepAlive => true;
}
Run Code Online (Sandbox Code Playgroud)

关于我的解决方案中的路由的注释

如果您在路由时遇到问题

Navigator.pushNamed(context, '/page3'); 
Run Code Online (Sandbox Code Playgroud)

或通过:

Navigator.of(context).pushNamed(Page3());
Run Code Online (Sandbox Code Playgroud)

您可以使用MaterialPageRoute修复它:

Navigator.pushReplacement(
  context,
  MaterialPageRoute(
    builder: (context) => Page3(),
  ),
);
Run Code Online (Sandbox Code Playgroud)


Hea*_*OSK -2

Navigator.of(context).pushNamed();用于带有页面转换的导航。所以,在这种情况下,方法是不匹配的。

您可以BottomNavigationBar与 一起使用Scaffold

示例代码:


class AppFooter extends StatefulWidget {
  @override
  _AppFooterState createState() => _AppFooterState();
}

class _AppFooterState extends State<AppFooter> {
  int _currentIndex = 0;

  List<Widget> _pages = [
    Text("page1"),
    Text("page2"),
    Text("page3"),
  ];


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _pages[_currentIndex],
      bottomNavigationBar: BottomNavigationBar(
        type: BottomNavigationBarType.fixed,
        currentIndex: _currentIndex,
        onTap: (int index) {
          setState(() {
            _currentIndex = index;
          });
        },
        items: [
          new BottomNavigationBarItem(
              backgroundColor: Colors.white,
              icon: _currentIndex == 0
                  ? new Image.asset('assets/images/dashboard_active.png')
                  : new Image.asset('assets/images/dashboard_inactive.png'),
              title:
                  new Text('Dashboard', style: new TextStyle(fontSize: 12.0))),
          new BottomNavigationBarItem(
              backgroundColor: Colors.white,
              icon: _currentIndex == 1
                  ? new Image.asset('assets/images/medical_sevice_active.png')
                  : new Image.asset(
                      'assets/images/medical_sevice_inactive.png'),
              title: new Text('Health Services',
                  style: new TextStyle(fontSize: 12.0))),
          new BottomNavigationBarItem(
              icon: InkWell(
                child: Icon(
                  Icons.format_align_left,
                  // color: green,
                  size: 20.0,
                ),
              ),
              title: new Text('History', style: new TextStyle(fontSize: 12.0))),
        ],
      ),
    );
  }
}

Run Code Online (Sandbox Code Playgroud)