Skip to content

Latest commit

Β 

History

History
443 lines (359 loc) Β· 10.9 KB

File metadata and controls

443 lines (359 loc) Β· 10.9 KB

Using AdaptiveConvexNavigation in Your Projects

πŸ“¦ Installation

Option 1: From pub.dev (When Published)

Add to your pubspec.yaml:

dependencies:
  adaptive_navigation: ^1.0.0  # Use latest version

Then run:

flutter pub get

Option 2: From Git Repository

Add to your pubspec.yaml:

dependencies:
  adaptive_navigation:
    git:
      url: https://github.com/your-username/adaptive_navigation.git
      ref: main  # or specific commit/tag

Option 3: Local Path (Development)

dependencies:
  adaptive_navigation:
    path: ../adaptive_navigation

πŸš€ Quick Start

1. Import the Package

import 'package:adaptive_navigation/adaptive_navigation.dart';

2. Basic Implementation

class MyHomePage extends StatefulWidget {
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _selectedIndex = 0;

  @override
  Widget build(BuildContext context) {
    return AdaptiveConvexNavigation(
      selectedIndex: _selectedIndex,
      onTap: (index) => setState(() => _selectedIndex = index),
      items: const [
        TabItem(icon: Icons.home, title: 'Home'),
        TabItem(icon: Icons.search, title: 'Search'),
        TabItem(icon: Icons.notifications, title: 'Alerts'),
        TabItem(icon: Icons.person, title: 'Profile'),
      ],
      child: _buildPageContent(),
    );
  }

  Widget _buildPageContent() {
    switch (_selectedIndex) {
      case 0:
        return HomePage();
      case 1:
        return SearchPage();
      case 2:
        return AlertsPage();
      case 3:
        return ProfilePage();
      default:
        return HomePage();
    }
  }
}

🎨 Common Use Cases

Use Case 1: Basic Adaptive Navigation

What you get:

  • Mobile: ConvexAppBar at bottom
  • Desktop: NavigationRail on side
  • Automatic switching at 600px
AdaptiveConvexNavigation(
  selectedIndex: _selectedIndex,
  onTap: (index) => setState(() => _selectedIndex = index),
  items: const [
    TabItem(icon: Icons.home, title: 'Home'),
    TabItem(icon: Icons.search, title: 'Search'),
    TabItem(icon: Icons.person, title: 'Profile'),
  ],
  child: MyContentWidget(),
)

Use Case 2: Notifications with Badges

Perfect for: Messaging apps, social media, any app with notifications

class _MyAppState extends State<MyApp> {
  int _selectedIndex = 0;
  
  // Badge state - hides when viewing, clears when read
  final Map<int, dynamic> _badges = {
    1: '5',    // 5 new messages
    2: '99+',  // 99+ notifications
  };

  // Visible badges (excludes active tab)
  Map<int, dynamic> get _visibleBadges {
    final visible = Map.from(_badges);
    visible.remove(_selectedIndex);
    return visible;
  }

  void _clearBadge(int index) {
    setState(() => _badges.remove(index));
  }

  @override
  Widget build(BuildContext context) {
    return AdaptiveConvexNavigation.badge(
      _visibleBadges,
      selectedIndex: _selectedIndex,
      onTap: (index) => setState(() => _selectedIndex = index),
      // Badge styling
      badgeColor: Colors.red,
      badgeTextColor: Colors.white,
      items: const [
        TabItem(icon: Icons.home, title: 'Home'),
        TabItem(icon: Icons.message, title: 'Messages'),
        TabItem(icon: Icons.notifications, title: 'Alerts'),
        TabItem(icon: Icons.person, title: 'Profile'),
      ],
      child: _buildContent(),
    );
  }
}

Use Case 3: Custom Styling

For branding: Match your app's design system

AdaptiveConvexNavigation(
  selectedIndex: _selectedIndex,
  onTap: _handleTap,
  // Custom breakpoint
  breakpoint: 800,
  
  // Mobile styling
  convexStyle: TabStyle.react,
  backgroundColor: Colors.deepPurple,
  activeColor: Colors.white,
  color: Colors.white70,
  gradient: LinearGradient(
    colors: [Colors.purple, Colors.blue],
  ),
  
  // Desktop styling
  railBackgroundColor: Colors.deepPurple,
  railLabelType: NavigationRailLabelType.all,
  railSelectedIconTheme: IconThemeData(color: Colors.white, size: 28),
  railUnselectedIconTheme: IconThemeData(color: Colors.white70, size: 24),
  
  items: const [...],
  child: MyContent(),
)

Use Case 4: E-Commerce App

class ShoppingAppNavigation extends StatefulWidget {
  @override
  State<ShoppingAppNavigation> createState() => _ShoppingAppNavigationState();
}

class _ShoppingAppNavigationState extends State<ShoppingAppNavigation> {
  int _selectedIndex = 0;
  int _cartItemCount = 3;

  @override
  Widget build(BuildContext context) {
    return AdaptiveConvexNavigation.badge(
      {2: _cartItemCount > 0 ? '$_cartItemCount' : null},
      selectedIndex: _selectedIndex,
      onTap: (index) => setState(() => _selectedIndex = index),
      backgroundColor: Theme.of(context).primaryColor,
      items: const [
        TabItem(icon: Icons.home, title: 'Home'),
        TabItem(icon: Icons.search, title: 'Search'),
        TabItem(icon: Icons.shopping_cart, title: 'Cart'),
        TabItem(icon: Icons.favorite, title: 'Wishlist'),
        TabItem(icon: Icons.person, title: 'Account'),
      ],
      child: _buildShoppingContent(),
    );
  }
}

Use Case 5: Social Media App

class SocialAppNavigation extends StatefulWidget {
  @override
  State<SocialAppNavigation> createState() => _SocialAppNavigationState();
}

class _SocialAppNavigationState extends State<SocialAppNavigation> {
  int _selectedIndex = 0;
  
  final Map<int, dynamic> _notifications = {
    2: '12',  // Messages
    3: Icons.circle,  // Activity dot
  };

  @override
  Widget build(BuildContext context) {
    return AdaptiveConvexNavigation.badge(
      _getVisibleBadges(),
      selectedIndex: _selectedIndex,
      onTap: _handleNavigation,
      convexStyle: TabStyle.reactCircle,
      items: const [
        TabItem(icon: Icons.home, title: 'Feed'),
        TabItem(icon: Icons.search, title: 'Explore'),
        TabItem(icon: Icons.message, title: 'Messages'),
        TabItem(icon: Icons.notifications, title: 'Activity'),
        TabItem(icon: Icons.person, title: 'Profile'),
      ],
      child: _buildFeed(),
    );
  }
  
  Map<int, dynamic> _getVisibleBadges() {
    final badges = Map<int, dynamic>.from(_notifications);
    badges.remove(_selectedIndex);
    return badges;
  }
}

πŸ“± Platform-Specific Behavior

The widget automatically adapts to different screen sizes:

Platform Small Screen Large Screen
iOS ConvexAppBar (bottom) NavigationRail (side)
Android ConvexAppBar (bottom) NavigationRail (side)
Web ConvexAppBar (bottom) NavigationRail (side)
Desktop N/A NavigationRail (side)

Breakpoint: 600px by default (customizable)

🎯 Best Practices

1. Badge State Management

// βœ… GOOD: Badges hide on active tab, reappear when navigating away
Map<int, dynamic> get _visibleBadges {
  final visible = Map.from(_badgeData);
  visible.remove(_selectedIndex);  // Hide active tab's badge
  return visible;
}

// ❌ BAD: Badges permanently disappear on tap
void _onTap(int index) {
  setState(() {
    _badges.remove(index);  // Don't do this!
  });
}

2. Clearing Badges

// βœ… GOOD: Clear badges from page content after action
void _markMessagesAsRead() {
  // Mark messages as read in your backend
  setState(() {
    _badges.remove(1);  // Then clear the badge
  });
}

// Use post-frame callback for button clicks
void _clearBadge(int index) {
  WidgetsBinding.instance.addPostFrameCallback((_) {
    if (mounted) {
      setState(() => _badges.remove(index));
    }
  });
}

3. Responsive Content

// βœ… GOOD: Your content should also be responsive
child: LayoutBuilder(
  builder: (context, constraints) {
    final isWide = constraints.maxWidth >= 600;
    return isWide
        ? DesktopLayout()
        : MobileLayout();
  },
)

4. Avoid Nested Scaffolds

// ❌ BAD: Don't nest Scaffolds
child: Scaffold(  // AdaptiveConvexNavigation already creates Scaffold on mobile!
  appBar: AppBar(...),
  body: Content(),
)

// βœ… GOOD: Use Column with AppBar
child: Column(
  children: [
    AppBar(...),
    Expanded(child: Content()),
  ],
)

🎨 Styling Reference

ConvexAppBar Styles

TabStyle.fixed         // Fixed center convex
TabStyle.fixedCircle   // Fixed center with circle
TabStyle.react         // Convex follows selection
TabStyle.reactCircle   // Convex follows with circle
TabStyle.textIn        // Text animates in
TabStyle.titled        // Text always visible
TabStyle.flip          // Flip animation

Color Consistency

// Define theme colors
const primary = Colors.blue;
const activeColor = Colors.white;
const inactiveColor = Colors.white70;

AdaptiveConvexNavigation(
  // Mobile colors
  backgroundColor: primary,
  activeColor: activeColor,
  color: inactiveColor,
  
  // Desktop colors (match mobile)
  railBackgroundColor: primary,
  railSelectedIconTheme: IconThemeData(color: activeColor),
  railUnselectedIconTheme: IconThemeData(color: inactiveColor),
  // ...
)

πŸ“š Complete API Reference

See ADAPTIVE_NAVIGATION.md for full API documentation.

πŸ”§ Troubleshooting

Badge not appearing

  • Check that badge data exists for that index
  • Ensure badge data is not null or empty string
  • Verify active tab's badge is being hidden intentionally

Exception when clicking buttons

  • Use WidgetsBinding.instance.addPostFrameCallback for state updates
  • Add mounted check before calling setState
  • Use ValueKey for widgets that change state

Layout issues on web

  • Avoid nested Scaffolds
  • Use Column instead of Scaffold for child content
  • Test at different breakpoints

Badges not disappearing

  • Check that you're removing from the correct index
  • Verify _visibleBadges getter is excluding active tab
  • Ensure setState is being called

πŸŽ“ Full Example

See example/lib/adaptive_badge_example.dart for a complete, production-ready implementation with:

  • βœ… Badge state management
  • βœ… Clear badge functionality
  • βœ… Responsive design
  • βœ… Multiple tab types
  • βœ… Custom styling

πŸ“– Additional Resources

  • API Documentation: See inline documentation in source code
  • Examples: Check example/ folder for working demos
  • Styling Guide: See doc/adaptive-navigation.md
  • Badge Improvements: See doc/badge-improvements.md

πŸ’‘ Tips

  1. Start Simple: Begin with basic implementation, add features as needed
  2. Test Responsive: Always test at multiple screen sizes
  3. Badge Behavior: Follow platform conventions for notification badges
  4. Styling: Match your app's theme for consistent user experience
  5. Performance: Use const constructors where possible

πŸš€ Ready to Ship!

Your navigation is now:

  • βœ… Responsive (mobile + desktop)
  • βœ… Beautiful (ConvexAppBar + NavigationRail)
  • βœ… Functional (badges, theming, animations)
  • βœ… Production-ready (error-free, tested)

Happy coding! πŸŽ‰