Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Navbar hides when pushing a new screen from floatingActionButton. #46

Closed
pavittarsingh315 opened this issue Jun 27, 2022 · 7 comments
Closed

Comments

@pavittarsingh315
Copy link

So basically I want a floating action button to be present on all screen. For this I am implementing it like so:

PersistentTabView.custom(
      ...
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          pushNewScreen(
            context,
            screen: Container(
              color: Colors.red,
            ),
            withNavBar: true,
          );
        },
      ),
      ...
);

The issue is that when this new screen is pushed, the navbar becomes hidden even though the withNavBar: true property.
Is this by design or is this fixable?

@pavittarsingh315
Copy link
Author

pavittarsingh315 commented Jun 27, 2022

I have actually found another issue with the floating action button. Flutter throws a multiple heroes exception.

The Stack ════════ Exception caught by scheduler library ═════════════════════════════════ The following assertion was thrown during a scheduler callback: There are multiple heroes that share the same tag within a subtree.

Within each subtree for which heroes are to be animated (i.e. a PageRoute subtree), each Hero must have a unique non-null tag.
In this case, multiple heroes had the following tag:
Here is the subtree for one of the offending heroes: Hero
tag:
state: _HeroState#29d09
When the exception was thrown, this was the stack
0 Hero._allHeroesFor.inviteHero.
1 Hero._allHeroesFor.inviteHero
2 Hero._allHeroesFor.visitor
3 SingleChildRenderObjectElement.visitChildren
4 Hero._allHeroesFor.visitor
5 ComponentElement.visitChildren
6 Hero._allHeroesFor.visitor
7 ComponentElement.visitChildren
8 Hero._allHeroesFor.visitor
9 MultiChildRenderObjectElement.visitChildren
10 Hero._allHeroesFor.visitor
11 ComponentElement.visitChildren
12 Hero._allHeroesFor.visitor
13 SingleChildRenderObjectElement.visitChildren
14 Hero._allHeroesFor.visitor
15 ComponentElement.visitChildren
16 Hero._allHeroesFor.visitor
17 SingleChildRenderObjectElement.visitChildren
18 Hero._allHeroesFor.visitor
19 ComponentElement.visitChildren
20 Hero._allHeroesFor.visitor
21 ComponentElement.visitChildren
22 Hero._allHeroesFor.visitor
23 ComponentElement.visitChildren
24 Hero._allHeroesFor.visitor
25 SingleChildRenderObjectElement.visitChildren
26 Hero._allHeroesFor.visitor
27 ComponentElement.visitChildren
28 Hero._allHeroesFor.visitor
29 ComponentElement.visitChildren
30 Hero._allHeroesFor.visitor
31 ComponentElement.visitChildren
32 Hero._allHeroesFor.visitor
33 SingleChildRenderObjectElement.visitChildren
34 Hero._allHeroesFor.visitor
35 MultiChildRenderObjectElement.visitChildren
36 Hero._allHeroesFor.visitor
37 SingleChildRenderObjectElement.visitChildren
38 Hero._allHeroesFor.visitor
39 ComponentElement.visitChildren
40 Hero._allHeroesFor.visitor
41 SingleChildRenderObjectElement.visitChildren
42 Hero._allHeroesFor.visitor
43 ComponentElement.visitChildren
44 Hero._allHeroesFor.visitor
45 ComponentElement.visitChildren
46 Hero._allHeroesFor.visitor
47 SingleChildRenderObjectElement.visitChildren
48 Hero._allHeroesFor.visitor
49 SingleChildRenderObjectElement.visitChildren
50 Hero._allHeroesFor.visitor
51 ComponentElement.visitChildren
52 Hero._allHeroesFor.visitor
53 ComponentElement.visitChildren
54 Hero._allHeroesFor.visitor
55 MultiChildRenderObjectElement.visitChildren
56 Hero._allHeroesFor.visitor
57 SingleChildRenderObjectElement.visitChildren
58 Hero._allHeroesFor.visitor
59 ComponentElement.visitChildren
60 Hero._allHeroesFor.visitor
61 SingleChildRenderObjectElement.visitChildren
62 Hero._allHeroesFor.visitor
63 MultiChildRenderObjectElement.visitChildren
64 Hero._allHeroesFor.visitor
65 SingleChildRenderObjectElement.visitChildren
66 Hero._allHeroesFor.visitor
67 ComponentElement.visitChildren
68 Hero._allHeroesFor.visitor
69 ComponentElement.visitChildren
70 Hero._allHeroesFor.visitor
71 ComponentElement.visitChildren
72 Hero._allHeroesFor.visitor
73 ComponentElement.visitChildren
74 Hero._allHeroesFor.visitor
75 ComponentElement.visitChildren
76 Hero._allHeroesFor.visitor
77 ComponentElement.visitChildren
78 Hero._allHeroesFor.visitor
79 SingleChildRenderObjectElement.visitChildren
80 Hero._allHeroesFor.visitor
81 ComponentElement.visitChildren
82 Hero._allHeroesFor.visitor
83 SingleChildRenderObjectElement.visitChildren
84 Element.visitChildElements
85 Hero._allHeroesFor
86 HeroController._startHeroTransition
87 HeroController._maybeStartHeroTransition.
88 SchedulerBinding._invokeFrameCallback
89 SchedulerBinding.handleDrawFrame
90 SchedulerBinding._handleDrawFrame
94 _invoke (dart:ui/hooks.dart:151:10)
95 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:308:5)
96 _drawFrame (dart:ui/hooks.dart:115:31)
(elided 3 frames from dart:async)
═══════════════════════════════════════════════════════════════════════════════

@jb3rndt
Copy link
Owner

jb3rndt commented Jul 1, 2022

The withNavBar: true will work correctly again if you set selectedTabScreenContext: (context) => currentTabContext = context, on PersistentTabView and use currentTabContext in your pushNewScreen function.

Regarding the multiple heroes: Do you know when exactly it happens?

@pavittarsingh315
Copy link
Author

I actually managed to fix the multiple heroes exception. That was being cause by another package which I ultimately removed and implemented myself.

As for the navbar solution, what is exactly currentTabContext? I don't have it defined and therefore I don't know what it is.

@jb3rndt
Copy link
Owner

jb3rndt commented Jul 10, 2022

It is just a variable that holds the BuildContext of the currently active tab. You can just define it in the widget where you use PersistentTabView like BuildContext currentTabContext. It has to be a stateful widget then though

@pavittarsingh315
Copy link
Author

pavittarsingh315 commented Jul 11, 2022

Sorry I'm having a hard time comprehending this. Like what exactly is currentTabContext? How do I assign it to the context of the currently active tab/how do I get the context of the current tab?

Could you please provide a code snippet?

@jb3rndt
Copy link
Owner

jb3rndt commented Jul 28, 2022

This should work

class CustomWidgetExample extends StatefulWidget {
  CustomWidgetExample({Key key}) : super(key: key);

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

class _CustomWidgetExampleState extends State<CustomWidgetExample> {
  PersistentTabController _controller;
  BuildContext currentTabContext;

  @override
  void initState() {
    super.initState();
    _controller = PersistentTabController(initialIndex: 0);
  }

  List<Widget> _buildScreens() {
    return [
      MainScreen(),
      MainScreen(),
      MainScreen(),
      MainScreen(),
      MainScreen(),
    ];
  }

  List<PersistentBottomNavBarItem> _navBarsItems() {
    return [
      PersistentBottomNavBarItem(
        icon: Icon(Icons.home),
        title: "Home",
        activeColorPrimary: Colors.blue,
        inactiveColorPrimary: Colors.grey,
      ),
      PersistentBottomNavBarItem(
        icon: Icon(Icons.search),
        title: ("Search"),
        activeColorPrimary: Colors.teal,
        inactiveColorPrimary: Colors.grey,
      ),
      PersistentBottomNavBarItem(
        icon: Icon(Icons.add),
        title: ("Add"),
        activeColorPrimary: Colors.deepOrange,
        inactiveColorPrimary: Colors.grey,
      ),
      PersistentBottomNavBarItem(
        icon: Icon(Icons.settings),
        title: ("Settings"),
        activeColorPrimary: Colors.indigo,
        inactiveColorPrimary: Colors.grey,
      ),
      PersistentBottomNavBarItem(
        icon: Icon(Icons.settings),
        title: ("Settings"),
        activeColorPrimary: Colors.indigo,
        inactiveColorPrimary: Colors.grey,
      ),
    ];
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Navigation Bar Demo')),
      body: PersistentTabView.custom(
        context,
        controller: _controller,
        screens: _buildScreens(),
        items: _navBarsItems(),
        itemCount: 5,
        customWidget: (navBarEssentials) => CustomNavBarWidget(
          items: _navBarsItems(),
          onItemSelected: (index) {
            setState(() {
              navBarEssentials.onItemSelected(index);
            });
          },
          selectedIndex: _controller.index,
        ),
        selectedTabScreenContext: (context) => currentTabContext = context,
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            pushNewScreen(
              currentTabContext,
              screen: Container(
                color: Colors.red,
              ),
              withNavBar: true,
            );
          },
        ),
      ),
    );
  }
}

class CustomNavBarWidget extends StatelessWidget {
  final int selectedIndex;
  final List<PersistentBottomNavBarItem> items;
  final ValueChanged<int> onItemSelected;

  CustomNavBarWidget({
    Key key,
    this.selectedIndex,
    @required this.items,
    this.onItemSelected,
  });

  Widget _buildItem(PersistentBottomNavBarItem item, bool isSelected) {
    return Container(
      alignment: Alignment.center,
      height: kBottomNavigationBarHeight,
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          Flexible(
            child: IconTheme(
              data: IconThemeData(
                  size: 26.0,
                  color: isSelected
                      ? (item.activeColorSecondary == null
                          ? item.activeColorPrimary
                          : item.activeColorSecondary)
                      : item.inactiveColorPrimary == null
                          ? item.activeColorPrimary
                          : item.inactiveColorPrimary),
              child: isSelected ? item.icon : item.inactiveIcon ?? item.icon,
            ),
          ),
          Padding(
            padding: const EdgeInsets.only(top: 5.0),
            child: Material(
              type: MaterialType.transparency,
              child: FittedBox(
                child: Text(
                  item.title,
                  style: TextStyle(
                      color: isSelected
                          ? (item.activeColorSecondary == null
                              ? item.activeColorPrimary
                              : item.activeColorSecondary)
                          : item.inactiveColorPrimary,
                      fontWeight: FontWeight.w400,
                      fontSize: 12.0),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
      child: Container(
        width: double.infinity,
        height: kBottomNavigationBarHeight,
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: items.map((item) {
            int index = items.indexOf(item);
            return Expanded(
              child: InkWell(
                onTap: () {
                  this.onItemSelected(index);
                },
                child: _buildItem(item, selectedIndex == index),
              ),
            );
          }).toList(),
        ),
      ),
    );
  }
}

@pavittarsingh315
Copy link
Author

Thank you. It works as intended now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants