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
150
points
267
downloads

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

Documentation

API reference

License

MIT (license)

Dependencies

analyzer, build, flutter, source_gen

More

Packages that depend on flutter_navkit