Skip to main content

flutter_navkit 2.0.2 copy "flutter_navkit: ^2.0.2" to clipboard
flutter_navkit: ^2.0.2 copied to clipboard

A powerful navigation toolkit for Flutter with type-safe routing, automatic route generation, and comprehensive navigation observability.

example/example.md

🧭 Flutter NavKit - Examples #

Simple examples demonstrating both routing approaches in NavKit.


🎨 Generated Routes Example #

This example shows how to use programmatic route generation with NavKitGeneratedRoute.

Complete Code: #

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

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return NavkitMaterialApp.onGenerateRoute(
      title: 'NavKit Generated Routes Example',
      debugShowCheckedModeBanner: false,
      observeWithStack: true,

      /// Define all routes with custom transitions
      generatedRoutes: [
        NavKitGeneratedRoute(
          name: '/',
          builder: (settings) => const HomeScreen(),
          transitionType: NavKitGeneratedRouteTransitionType.fade,
        ),
        NavKitGeneratedRoute(
          name: '/profile',
          builder: (settings) => const ProfileScreen(),
          transitionType: NavKitGeneratedRouteTransitionType.slideRight,
          duration: const Duration(milliseconds: 400),
        ),
        NavKitGeneratedRoute(
          name: '/details',
          builder: (settings) {
            // Extract arguments from settings
            final args = settings.arguments as Map<String, dynamic>?;
            final title = args?['title'] as String? ?? 'No Title';
            final id = args?['id'] as int? ?? 0;
            
            return DetailsScreen(title: title, id: id);
          },
          transitionType: NavKitGeneratedRouteTransitionType.scale,
        ),
      ],

      /// Fallback route for unknown routes
      generatedFailureRoute: NavKitGeneratedRoute(
        builder: (settings) => const NotFoundScreen(),
        transitionType: NavKitGeneratedRouteTransitionType.fade,
      ),
    );
  }
}

// ═══════════════════════════════════════════════════════════
// HOME SCREEN
// ═══════════════════════════════════════════════════════════
class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Home')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text(
              'Generated Routes Example',
              style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 32),

            // Navigate to profile
            ElevatedButton(
              onPressed: () => context.toNamed('/profile'),
              child: const Text('Go to Profile'),
            ),
            const SizedBox(height: 16),

            // Navigate with arguments
            ElevatedButton(
              onPressed: () => context.toNamed(
                '/details',
                args: {'title': 'Product A', 'id': 42},
              ),
              child: const Text('View Details'),
            ),
            const SizedBox(height: 16),

            // Test 404 page
            ElevatedButton(
              onPressed: () => context.toNamed('/nonexistent'),
              child: const Text('Go to Unknown Route (404)'),
            ),
          ],
        ),
      ),
    );
  }
}

// ═══════════════════════════════════════════════════════════
// PROFILE SCREEN
// ═══════════════════════════════════════════════════════════
class ProfileScreen extends StatelessWidget {
  const ProfileScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Profile')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const CircleAvatar(
              radius: 50,
              child: Icon(Icons.person, size: 50),
            ),
            const SizedBox(height: 16),
            const Text(
              'John Doe',
              style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 32),
            ElevatedButton(
              onPressed: () => context.back(),
              child: const Text('Go Back'),
            ),
          ],
        ),
      ),
    );
  }
}

// ═══════════════════════════════════════════════════════════
// DETAILS SCREEN (With Arguments)
// ═══════════════════════════════════════════════════════════
class DetailsScreen extends StatelessWidget {
  final String title;
  final int id;

  const DetailsScreen({
    super.key,
    required this.title,
    required this.id,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Details')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              title,
              style: const TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 8),
            Text(
              'ID: $id',
              style: const TextStyle(fontSize: 16, color: Colors.grey),
            ),
            const SizedBox(height: 32),
            ElevatedButton(
              onPressed: () => context.back(),
              child: const Text('Go Back'),
            ),
          ],
        ),
      ),
    );
  }
}

// ═══════════════════════════════════════════════════════════
// NOT FOUND SCREEN (404)
// ═══════════════════════════════════════════════════════════
class NotFoundScreen extends StatelessWidget {
  const NotFoundScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('404 - Not Found')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Icon(Icons.error_outline, size: 80, color: Colors.red),
            const SizedBox(height: 16),
            const Text(
              'Page Not Found',
              style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 8),
            const Text('The page you are looking for does not exist.'),
            const SizedBox(height: 32),
            ElevatedButton(
              onPressed: () => context.toNamed('/'),
              child: const Text('Go Home'),
            ),
          ],
        ),
      ),
    );
  }
}

Key Features Demonstrated: #

✅ Route definition with NavKitGeneratedRoute
✅ Custom transitions per route (fade, slideRight, scale)
✅ Route arguments using RouteSettings in the builder
✅ Custom 404 page with generatedFailureRoute
✅ Navigation methods (toNamed, back)
✅ Stack logging with observeWithStack: true


📝 Annotated Routes Example #

This example shows how to use annotation-based automatic route generation with @NavkitRoute.

Step 1: Define Your Screens with Annotations #

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

// Import the generated routes file
import 'main.navkit.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return NavkitMaterialApp.annotatedRoute(
      title: 'NavKit Annotated Routes Example',
      debugShowCheckedModeBanner: false,
      observeWithStack: true,

      /// List all annotated screens
      /// The initial route MUST be first!
      navkitRoutes: const [
        HomeScreen(),    // Must be first (marked as initial)
        ProfileScreen(),
        DetailsScreen(),
      ],
    );
  }
}

// ═══════════════════════════════════════════════════════════
// HOME SCREEN (Initial Route)
// ═══════════════════════════════════════════════════════════
@NavkitRoute(isInitial: true)
class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Home')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text(
              'Annotated Routes Example',
              style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 32),

            // Named navigation using generated constants
            ElevatedButton(
              onPressed: () => context.toNamed(NavkitRoutes.profileScreen),
              child: const Text('Go to Profile (Named)'),
            ),
            const SizedBox(height: 16),

            // Direct widget navigation
            ElevatedButton(
              onPressed: () => context.to(const ProfileScreen()),
              child: const Text('Go to Profile (Direct)'),
            ),
            const SizedBox(height: 16),

            // Navigate with arguments
            ElevatedButton(
              onPressed: () => context.toNamed(
                NavkitRoutes.detailsScreen,
                args: {'title': 'Product A', 'id': 42},
              ),
              child: const Text('View Details'),
            ),
            const SizedBox(height: 16),

            // With fade animation
            ElevatedButton(
              onPressed: () => context.toWithFade(const ProfileScreen()),
              child: const Text('Go to Profile (Fade)'),
            ),
          ],
        ),
      ),
    );
  }
}

// ═══════════════════════════════════════════════════════════
// PROFILE SCREEN
// ═══════════════════════════════════════════════════════════
@NavkitRoute()
class ProfileScreen extends StatelessWidget {
  const ProfileScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Profile')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const CircleAvatar(
              radius: 50,
              child: Icon(Icons.person, size: 50),
            ),
            const SizedBox(height: 16),
            const Text(
              'John Doe',
              style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 32),

            // Navigate to details
            ElevatedButton(
              onPressed: () => context.toNamed(NavkitRoutes.detailsScreen),
              child: const Text('View Details'),
            ),
            const SizedBox(height: 16),

            // Go back
            ElevatedButton(
              onPressed: () => context.back(),
              child: const Text('Go Back'),
            ),
            const SizedBox(height: 16),

            // Back to home
            ElevatedButton(
              onPressed: () => context.backToNamed(NavkitRoutes.homeScreen),
              child: const Text('Back to Home'),
            ),
          ],
        ),
      ),
    );
  }
}

// ═══════════════════════════════════════════════════════════
// DETAILS SCREEN (Receives Arguments)
// ═══════════════════════════════════════════════════════════
@NavkitRoute()
class DetailsScreen extends StatelessWidget {
  const DetailsScreen({super.key});

  @override
  Widget build(BuildContext context) {
    // Extract arguments
    final args = context.arguments<Map<String, dynamic>>();
    final title = args?['title'] ?? 'No Title';
    final id = args?['id'] ?? 0;

    return Scaffold(
      appBar: AppBar(title: const Text('Details')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              title,
              style: const TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 8),
            Text(
              'ID: $id',
              style: const TextStyle(fontSize: 16, color: Colors.grey),
            ),
            const SizedBox(height: 32),

            ElevatedButton(
              onPressed: () => context.back(),
              child: const Text('Go Back'),
            ),
            const SizedBox(height: 16),

            ElevatedButton(
              onPressed: () => context.backToFirst(),
              child: const Text('Back to First'),
            ),
          ],
        ),
      ),
    );
  }
}

Step 2: Create build.yaml #

Create a build.yaml file in your project root:

targets:
  $default:
    builders:
      flutter_navkit|navkit_routes_builder:
        enabled: true

Step 3: Generate Routes #

Run this command to generate the route constants:

dart run build_runner build --delete-conflicting-outputs

This generates lib/main.navkit.dart:

class NavkitRoutes {
  NavkitRoutes._();

  /// Route name for HomeScreen
  static const String homeScreen = '/';

  /// Route name for ProfileScreen
  static const String profileScreen = '/profileScreenRoute';

  /// Route name for DetailsScreen
  static const String detailsScreen = '/detailsScreenRoute';

  /// All registered routes
  static const Map<String, String> all = {
    'HomeScreen': '/',
    'ProfileScreen': '/profileScreenRoute',
    'DetailsScreen': '/detailsScreenRoute',
  };
}

Key Features Demonstrated: #

✅ Annotation-based routing with @NavkitRoute()
✅ Auto-generated route constants (NavkitRoutes.screenName)
✅ Initial route marking with isInitial: true
✅ Type-safe navigation using generated constants
✅ Multiple navigation methods (named, direct, animated)
✅ Argument handling with context.arguments<T>()
✅ Stack management (back, backToNamed, backToFirst)


🎯 Comparison #

Feature Generated Routes Annotated Routes
Setup Define routes in list Annotate classes + run build_runner
Route Names Manual ('/', '/profile') Auto-generated (NavkitRoutes.profileScreen)
Type Safety String-based Constant-based
Arguments In builder function In widget build method
Transitions Per-route config Per-navigation call
404 Handling Custom generatedFailureRoute Default screen
Build Runner ❌ Not needed ✅ Required

📚 Next Steps #

4
likes
130
points
44
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A powerful navigation toolkit for Flutter with type-safe routing, automatic route generation, and comprehensive navigation observability.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

analyzer, build, flutter, source_gen

More

Packages that depend on flutter_navkit