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

Add NavigationView.paneBodyBuilder #553

Merged
merged 3 commits into from
Oct 8, 2022

Conversation

klondikedragon
Copy link
Contributor

@klondikedragon klondikedragon commented Oct 1, 2022

Useful to override the widget used as the body of the navigation view in conjunction with pane items. This can be useful if you are using router-based navigation, and the body of the navigation pane should be determined by the current route rather than just by the currently selected pane.

This resolves #548.

It allows 4.0.x to be compatible with the approach described in #226 (comment) with the following modification to MyAppNavBar widget:

Example use of paneBodyBuilder
...
class _MyAppNavBarState extends ConsumerState<MyAppNavBar> {
  // Will be populated on demand as each of the navbar panes is visited (if ever).
  List<Widget> panes = List.filled(topNavPages.length, Container());
  // Track the last specific route we were using within a given nav pane, so that
  // we can restore the full sub-route when we go back to that particular nav pane.
  List<String> paneLastVisitedUrls = List.from(topNavPages);

  @override
  Widget build(BuildContext context) {
    // Populate current widget and route for the currently selected pane.
    panes[widget.currentTabIndex] = widget.child;
    paneLastVisitedUrls[widget.currentTabIndex] = context.vRouter.url;

    return material.Scaffold(
        body: NavigationView(
      pane: NavigationPane(
        selected: (widget.currentTabIndex >= 0 &&
                widget.currentTabIndex < numPaneItems)
            ? widget.currentTabIndex
            : null,
        onChanged: (i) => context.vRouter.to(paneLastVisitedUrls[i]),
        // TODO: Watch this until https://github.com/bdlukaa/fluent_ui/issues/173 is fixed
        indicatorBuilder: NavigationIndicator.sticky,
        //size: const NavigationPaneSize(),
        header: ...,
        displayMode: PaneDisplayMode.compact,
        items: [
            PaneItem(icon: ..., Text('Home'), body: const SizedBox.shrink()),
            PaneItem(icon: ..., Text('Pane 2'), body: const SizedBox.shrink()),
            PaneItem(icon: ..., Text('Pane 3'), body: const SizedBox.shrink()),
            PaneItem(icon: ..., Text('Pane 4'), body: const SizedBox.shrink()),
        ],
        footerItems: [
          PaneItemSeparator(),
          PaneItem(icon: ..., Text('Pane 5'), const SizedBox.shrink()),
        ],
      ),
      // Use IndexedStack instead of NavigationBody so that the state
      // of the children pages are preserved between navigations
      paneBodyBuilder: (viewWidget, selectedIndex, selectedPaneItemBody) =>
          NavigationBody(
        itemKey: ValueKey(selectedIndex ?? -1),
        transitionBuilder: viewWidget.transitionBuilder,
        child: IndexedStack(
          index: widget.currentTabIndex,
          children: panes,
        ),
      ),
    ));
  }
}

Pre-launch Checklist

  • I have updated CHANGELOG.md with my changes
  • I have run "dart format ." on the project
  • I have added/updated relevant documentation

Useful to override the widget used as the body of the navigation view in
conjunction with pane items. This can be useful if you are using
router-based navigation, and the body of the navigation pane should be
determined by the current route rather than just by the currently
selected pane.
@bdlukaa
Copy link
Owner

bdlukaa commented Oct 2, 2022

I don't like the design of this implementation. NavigationBody was made private to make the animation consistent with other properties/features of NavigationView. If we'd have dynamic content, I'd make a Widget content property, which would show the current body.

Make `_NavigationBody` private again.
@klondikedragon
Copy link
Contributor Author

@bdlukaa - I've refactored, see if you like this second approach better. It makes _NavigationBody private again and doesn't require the builder callback to know anything about its internals, but it still allows the dynamic pane content to benefit from the animation provided by it.

Another option would be to just have it pass through and use the content widget if it's non-null in the place of pane.selectedItem.body. That would also work for me, but perhaps be a little less flexible for other use cases that might want to dynamically adapt the contents of the current pane item body. I'm happy to change the PR to this third approach if you prefer it.

@bdlukaa bdlukaa merged commit c5e9e5d into bdlukaa:master Oct 8, 2022
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

Successfully merging this pull request may close these issues.

make PaneItem.body is not required and make the pane and the content can be exist on one time
2 participants