🎯 The Problem with Default Navigation
Let's be honest: Flutter's default BottomNavigationBar works, but it's... boring. In today's competitive app market, user experience and visual polish can make or break your application. Users expect more than just functionality—they crave delightful interactions and smooth animations.
I set out to build something different: a navigation bar that doesn't just work, but feels alive.
✨ The Vision: Beyond Basic Navigation
I wanted to create a navigation component that:
- Feels natural with physics-based movements
- Delights users with every tap
- Adapts intelligently to user behavior
- Looks premium without sacrificing performance
The result? A floating navbar that combines:
- 🎯 Magnetic snapping - Tabs snap into place like they're magnetically attracted
- 🌊 Spring physics - Every movement has natural bounce and momentum
- 🔄 Shared axis transitions - Smooth morphing between states
- 📉 Scroll-aware behavior - Intelligently hides when you scroll down
🧠 The Physics Behind the Magic
Spring Animations: The Secret Sauce
Instead of traditional easing curves, I implemented physics-based spring animations. Here's why:
// Traditional animation
AnimatedContainer(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
)
// Physics-based animation
SpringAnimation(
spring: SpringDescription(
mass: 1.0,
stiffness: 300,
damping: 30,
),
)
Spring animations feel more natural because they mimic real-world physics. When you tap a tab, it doesn't just move—it bounces slightly, like a physical object responding to force.
The 40px Scroll Threshold
One subtle but important detail: the navbar only hides after scrolling 40px. This prevents accidental hiding during small scroll movements or when users are just exploring.
void _onScroll() {
if (_scrollController.position.pixels > 40) {
// Hide navbar
} else {
// Show navbar
}
}
🎨 Design Decisions
Pill Morph Animation
The selected tab expands into a pill shape, creating a clear visual hierarchy. This uses Flutter's powerful animation system to smoothly interpolate between shapes:
AnimatedContainer(
width: selected ? expandedWidth : collapsedWidth,
height: 56,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(selected ? 28 : 16),
color: selected ? accentColor : Colors.transparent,
),
)
Dynamic Color Shifts
Each tab has its own accent color that subtly influences the navbar's appearance when selected. This creates a visual connection between the navbar and the content.
Dark Glass Effect
Using Flutter's BackdropFilter, I added a subtle blur effect that gives the navbar a modern, premium look:
ClipRRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
child: Container(
color: Colors.white.withOpacity(0.1),
),
),
)
🚀 Implementation Challenges
Challenge 1: Hit Testing
With a floating navbar, touch targets need to be precise. I optimized the hit testing to ensure users never miss a tap:
@override
bool hitTest(Offset position) {
// Custom hit test logic for floating position
return _isPointWithinNavbar(position);
}
Challenge 2: Performance
Multiple animations running simultaneously could cause jank. Solution? Heavy optimization:
- Used
constconstructors where possible - Minimized rebuilds with
AnimatedBuilder - Cached expensive calculations
Challenge 3: Overflow Handling
Different screen sizes need different layouts. The navbar adapts by:
- Dynamically calculating label widths
- Adding overflow protection
- Maintaining touch targets size
💡 Key Takeaways
1. Physics > Curves
Spring animations might be more complex, but they create a significantly better user experience. Users might not notice consciously, but they'll feel the difference.
2. Thresholds Matter
The 40px scroll threshold wasn't random—it came from user testing. Too sensitive, and users get frustrated; too lenient, and the feature is useless.
3. Polish is in the Details
The magnetic snapping, the subtle blur, the dynamic colors—each individually is small, but together they create a premium feel.
🛠️ How to Use It
Ready to try it yourself? Here's how:
// 1. Add to your Scaffold
Scaffold(
body: yourContent,
bottomNavigationBar: CustomFloatingNavbar(
items: [
NavItem(Icons.home, "Home"),
NavItem(Icons.search, "Search"),
NavItem(Icons.favorite, "Likes"),
NavItem(Icons.person, "Profile"),
],
onItemSelected: (index) {
// Handle navigation
},
),
)
// 2. Make pages scrollable
SingleChildScrollView(
controller: scrollController,
child: yourContent,
)
📊 Performance Metrics
After extensive testing:
- 60fps animations on mid-range devices
- Zero frame drops during transitions
- < 2ms layout time
- Minimal memory footprint
🔮 Future Improvements
I'm planning to add:
- [ ] Custom theme builder
- [ ] More animation presets
- [ ] Gesture-based navigation
- [ ] Accessibility improvements
🎁 Try It Yourself!
The complete code is available on GitHub:
🔗 github.com/Damantha126/Floating-Navbar-M3
Give it a ⭐ if you find it useful!
💭 Final Thoughts
Building this navbar taught me that great UI is about feeling, not just function. When users interact with your app, every animation, every transition, every micro-interaction contributes to their overall impression.
Don't settle for default widgets. Push boundaries. Your users will thank you.
📫 Let's Connect!
- Portfolio: damanthaja.dev
- LinkedIn: linkedin.com/in/damanthajasinghe
- GitHub: @Damantha126
Have questions or want to contribute? Open an issue or PR on GitHub!
Flutter #UIDesign #MobileDev #OpenSource #Animation

Top comments (0)