snap_nav_bar 0.1.0 copy "snap_nav_bar: ^0.1.0" to clipboard
snap_nav_bar: ^0.1.0 copied to clipboard

A frosted, gesture-driven bottom navigation bar with loose swipe-to-preview paging, snap-on-release physics, tap-to-centre and haptic feedback.

snap_nav_bar #

A frosted, gesture-driven bottom navigation bar with loose swipe-to-preview paging, snap-on-release physics, tap-to-centre navigation and haptic feedback.

What it does #

  • Swipe the pages — the content PageView uses a soft custom spring so a flick glides and settles instead of snapping hard.
  • Swipe the bar — dragging the tab strip previews the move 1:1 under your finger while the page stays frozen; the page only commits (sliding smoothly) when you let go. A fast fling nudges one extra tab.
  • Tap any tab — near or far — and it slides straight to that page and centres it.
  • Haptics — a selection tick as each tab crosses centre and a soft impact when the page locks in. Both are swappable, or off entirely.
  • Frosted squircle surfaceBackdropFilter blur behind an iOS-style squircle strip, with a centre indicator over the active tab.

No AnimationController, Ticker, or flutter_animate — the strip easing is done with TweenAnimationBuilder and PageController animations only. Icons are arbitrary widgets you supply; the package has no SVG or asset dependency.

Install #

dependencies:
  snap_nav_bar: ^0.1.0

Usage #

The quickest path is SnapNavShell, which owns the content PageView and the bar and wires them together:

import 'package:flutter/material.dart';
import 'package:snap_nav_bar/snap_nav_bar.dart';

class Demo extends StatelessWidget {
  const Demo({super.key});

  @override
  Widget build(BuildContext context) {
    return SnapNavShell(
      items: const [
        SnapNavItem(
          icon: Icon(Icons.home_outlined),
          activeIcon: Icon(Icons.home_rounded),
          label: 'Home',
          page: ColoredBox(color: Color(0xFF3B82F6)),
        ),
        SnapNavItem(
          icon: Icon(Icons.search_rounded),
          label: 'Search',
          page: ColoredBox(color: Color(0xFF10B981)),
        ),
        SnapNavItem(
          icon: Icon(Icons.person_rounded),
          label: 'Profile',
          page: ColoredBox(color: Color(0xFFEF4444)),
        ),
      ],
      onTabChanged: (i) => debugPrint('tab $i'),
    );
  }
}

Want SVG icons? Pass an SvgPicture (or anything) as the icon — the package never touches SVG itself. Driving your own PageView? Use SnapNavBar directly with a PageController (viewportFraction: 1.0).

The bar is frosted, so it blurs whatever is painted behind it — keep it overlaid on your content (which SnapNavShell does for you).

See example/ for a runnable two-screen demo: one all-defaults, one heavily customised (6 tabs, solid floating pill, no blur, custom indicator, swapped haptics).

Parameters #

SnapNavShell exposes everything below. SnapNavBar exposes the same appearance, motion, indicator and feedback parameters (it takes a PageController and items instead of owning them, and viewportFraction / initialIndex / height live on the shell).

Content #

Parameter Type Default Description
items List<SnapNavItem> required Tabs; each carries icon, optional activeIcon, optional label, and its page. Min 1, any length.
initialIndex int 0 Tab shown first.
onTabChanged ValueChanged<int>? null Fires when the selected page changes.

Layout & motion #

Parameter Type Default Description
viewportFraction double 1.0 How much of each content page fills the viewport; below 1.0 the neighbouring pages peek in.
height double 76.0 Bar height above the bottom safe-area inset.
tabSpacing double 52.0 Logical px of finger travel per tab while dragging the strip.
horizontalMargin double 0.0 Space left/right of the bar.
bottomMargin double 0.0 Space below the bar (lifts it into a floating pill).
tapToCenterDuration Duration 300 ms Slide duration for a tab tap / drag release.
tapToCenterCurve Curve Curves.easeOutCubic Slide curve for the same.
activeOpacity double 1.0 Opacity of the centred tab.
inactiveOpacity double 0.5 Opacity of a fully off-centre tab (tabs crossfade between the two).
activeScale double 1.0 Scale of the centred tab.
inactiveScale double 0.92 Minimum scale an off-centre tab shrinks to.

Shape & surface #

Parameter Type Default Description
backgroundColor Color? Color(0x40808080) Bar fill (ignored if a gradient is set).
backgroundGradient Gradient? null Bar fill gradient; overrides backgroundColor.
cornerRadius double 32.0 Corner radius.
cornerSmoothing double 1.0 0.0 plain rounded rect → 1.0 full squircle.
blurSigma double? 24.0 Backdrop blur; null disables the frost entirely.
border BoxBorder? null Uniform border on the squircle edge.
boxShadow List<BoxShadow>? null Drop shadow, painted outside the clip.

Indicator #

Parameter Type Default Description
indicator Widget? null Custom centre indicator; null draws the built-in arrow.
showIndicator bool true Whether the indicator shows at all.
indicatorColor Color Color(0xFFE53935) Colour of the built-in arrow.
indicatorSize Size Size(12, 8) Indicator slot size.

Feedback #

Parameter Type Default Description
hapticsEnabled bool true Master haptics switch.
hapticFeedback void Function(SnapNavHaptic)? null Swap the effect fired at each trigger point. null uses selectionClick on cross and lightImpact on settle.

License #

MIT — see LICENSE.

1
likes
150
points
6
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A frosted, gesture-driven bottom navigation bar with loose swipe-to-preview paging, snap-on-release physics, tap-to-centre and haptic feedback.

Topics

#navigation #bottom-navigation #page-view #gestures #ui

License

MIT (license)

Dependencies

figma_squircle, flutter

More

Packages that depend on snap_nav_bar