Md Mominul Islam | Software and Data Enginnering | SQL Server, .NET, Power BI, Azure Blog

while(!(succeed=try()));

LinkedIn Portfolio Banner

Latest

Home Top Ad

Responsive Ads Here

Post Top Ad

Responsive Ads Here

Tuesday, August 26, 2025

Master Flutter & Dart: Module 5 - Navigation and Routing for Seamless Multi-Screen Apps

 


Table of Contents

  1. Introduction to Navigation in Flutter

  2. Basic Navigation with Navigator.push and Navigator.pop

    • 2.1 Understanding the Navigator Widget

    • 2.2 Implementing Navigator.push

    • 2.3 Using Navigator.pop

    • 2.4 Real-Life Example: A Shopping App Screen Transition

  3. Named Routes and Route Management

    • 3.1 Defining Named Routes

    • 3.2 Navigating with Named Routes

    • 3.3 Managing Routes with MaterialApp

    • 3.4 Real-Life Example: A Social Media App

  4. Passing Data Between Screens

    • 4.1 Passing Data with Navigator.push

    • 4.2 Returning Data with Navigator.pop

    • 4.3 Real-Life Example: A Note-Taking App

  5. Advanced Routing with go_router

    • 5.1 Setting Up go_router

    • 5.2 Configuring Routes and Sub-Routes

    • 5.3 Handling Query Parameters

    • 5.4 Real-Life Example: An E-Commerce App

  6. Handling Deep Links in Flutter Apps

    • 6.1 Understanding Deep Links

    • 6.2 Configuring Deep Links

    • 6.3 Handling Deep Links with go_router

    • 6.4 Real-Life Example: A News App

  7. Practical Exercise: Building a To-Do List App

    • 7.1 Project Setup

    • 7.2 Creating the List View Screen

    • 7.3 Creating the Detail View Screen

    • 7.4 Implementing Navigation and Data Passing

    • 7.5 Adding Deep Link Support

  8. Best Practices for Navigation in Flutter

  9. Pros and Cons of Navigation Approaches

  10. Alternatives to go_router

  11. Exception Handling in Navigation

  12. Conclusion


1. Introduction to Navigation in Flutter

Navigation is the backbone of any multi-screen mobile application. In Flutter, navigation allows users to move seamlessly between screens, whether it's to view details, submit forms, or access settings. This module focuses on mastering Flutter's navigation and routing techniques, from basic screen transitions to advanced routing with packages like go_router and handling deep links for real-world apps.

By the end of this module, you'll be able to:

  • Create multi-screen apps with smooth transitions.

  • Pass and retrieve data between screens.

  • Implement advanced routing with go_router.

  • Handle deep links to enhance user experience.

We'll use a practical to-do list app as a hands-on example, inspired by real-life scenarios like task management apps used daily.


2. Basic Navigation with Navigator.push and Navigator.pop

2.1 Understanding the Navigator Widget

Flutter's Navigator widget manages a stack of routes, where each route represents a screen. The stack operates on a "last in, first out" principle, meaning the most recently pushed screen is displayed, and popping removes it to reveal the previous screen.

2.2 Implementing Navigator.push

Navigator.push adds a new route to the stack, transitioning to a new screen. Here's a basic example:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: FirstScreen(),
    );
  }
}

class FirstScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('First Screen')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => SecondScreen()),
            );
          },
          child: Text('Go to Second Screen'),
        ),
      ),
    );
  }
}

class SecondScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Second Screen')),
      body: Center(child: Text('Welcome to the Second Screen!')),
    );
  }
}

Explanation:

  • Navigator.push takes a context and a Route (e.g., MaterialPageRoute).

  • MaterialPageRoute builds the new screen (SecondScreen) and animates the transition.

2.3 Using Navigator.pop

Navigator.pop removes the topmost screen, returning to the previous one:

class SecondScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Second Screen')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: Text('Go Back'),
        ),
      ),
    );
  }
}

Explanation:

  • Navigator.pop(context) removes SecondScreen from the stack, returning to FirstScreen.

2.4 Real-Life Example: A Shopping App Screen Transition

Imagine a shopping app where users browse products on the home screen and tap a product to view its details. Here's how you can implement this:

import 'package:flutter/material.dart';

void main() {
  runApp(ShoppingApp());
}

class ShoppingApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: ProductListScreen(),
    );
  }
}

class ProductListScreen extends StatelessWidget {
  final List<String> products = ['Laptop', 'Phone', 'Tablet'];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Product List')),
      body: ListView.builder(
        itemCount: products.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(products[index]),
            onTap: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => ProductDetailScreen(product: products[index]),
                ),
              );
            },
          );
        },
      ),
    );
  }
}

class ProductDetailScreen extends StatelessWidget {
  final String product;

  ProductDetailScreen({required this.product});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('$product Details')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Details for $product'),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                Navigator.pop(context);
              },
              child: Text('Back to List'),
            ),
          ],
        ),
      ),
    );
  }
}

Explanation:

  • The ProductListScreen displays a list of products.

  • Tapping a product uses Navigator.push to show ProductDetailScreen.

  • Navigator.pop returns to the product list.

Best Practices:

  • Use MaterialPageRoute for standard transitions.

  • Ensure the context is valid when calling Navigator methods.

  • Avoid excessive nesting of screens to prevent stack overflow.


3. Named Routes and Route Management

3.1 Defining Named Routes

Named routes simplify navigation by assigning string identifiers to screens. Define them in MaterialApp:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      initialRoute: '/',
      routes: {
        '/': (context) => HomeScreen(),
        '/details': (context) => DetailsScreen(),
      },
    );
  }
}

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Home')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.pushNamed(context, '/details');
          },
          child: Text('Go to Details'),
        ),
      ),
    );
  }
}

class DetailsScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Details')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: Text('Go Back'),
        ),
      ),
    );
  }
}

Explanation:

  • MaterialApp.routes maps route names to screen widgets.

  • Navigator.pushNamed navigates to the specified route.

3.2 Navigating with Named Routes

Use Navigator.pushNamed and Navigator.pop for navigation:

Navigator.pushNamed(context, '/details');
// To go back
Navigator.pop(context);

3.3 Managing Routes with MaterialApp

For dynamic routes, use onGenerateRoute:

MaterialApp(
  onGenerateRoute: (settings) {
    if (settings.name == '/details') {
      return MaterialPageRoute(
        builder: (context) => DetailsScreen(),
      );
    }
    return null; // Handle unknown routes
  },
)

3.4 Real-Life Example: A Social Media App

In a social media app, users navigate from a feed to a profile screen using named routes:

import 'package:flutter/material.dart';

void main() {
  runApp(SocialMediaApp());
}

class SocialMediaApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      initialRoute: '/feed',
      routes: {
        '/feed': (context) => FeedScreen(),
        '/profile': (context) => ProfileScreen(),
      },
    );
  }
}

class FeedScreen extends StatelessWidget {
  final List<String> posts = ['Post 1', 'Post 2', 'Post 3'];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Feed')),
      body: ListView.builder(
        itemCount: posts.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(posts[index]),
            onTap: () {
              Navigator.pushNamed(context, '/profile');
            },
          );
        },
      ),
    );
  }
}

class ProfileScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Profile')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: Text('Back to Feed'),
        ),
      ),
    );
  }
}

Explanation:

  • Routes are defined in MaterialApp.

  • Tapping a post navigates to the profile screen using Navigator.pushNamed.

Best Practices:

  • Use descriptive route names (e.g., /profile instead of /p).

  • Centralize route definitions for maintainability.

  • Handle unknown routes to avoid crashes.


4. Passing Data Between Screens

4.1 Passing Data with Navigator.push

Pass data by including it in the screen's constructor:

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => DetailsScreen(data: 'Some Data'),
  ),
);

4.2 Returning Data with Navigator.pop

Return data to the previous screen using Navigator.pop:

Navigator.pop(context, 'Result Data');

Receive the result in the calling screen:

final result = await Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => DetailsScreen()),
);

4.3 Real-Life Example: A Note-Taking App

In a note-taking app, users create a note and return it to the main screen:

import 'package:flutter/material.dart';

void main() {
  runApp(NoteApp());
}

class NoteApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: NoteListScreen(),
    );
  }
}

class NoteListScreen extends StatelessWidget {
  final List<String> notes = [];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Notes')),
      body: ListView.builder(
        itemCount: notes.length,
        itemBuilder: (context, index) {
          return ListTile(title: Text(notes[index]));
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          final newNote = await Navigator.push(
            context,
            MaterialPageRoute(builder: (context) => AddNoteScreen()),
          );
          if (newNote != null) {
            notes.add(newNote);
          }
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

class AddNoteScreen extends StatelessWidget {
  final TextEditingController _controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Add Note')),
      body: Padding(
        padding: EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextField(
              controller: _controller,
              decoration: InputDecoration(labelText: 'Note'),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                Navigator.pop(context, _controller.text);
              },
              child: Text('Save Note'),
            ),
          ],
        ),
      ),
    );
  }
}

Explanation:

  • NoteListScreen navigates to AddNoteScreen.

  • AddNoteScreen returns the note text using Navigator.pop.

  • The note is added to the list if not null.

Best Practices:

  • Validate data before passing to avoid null errors.

  • Use immutable data models for complex objects.

  • Handle null returns gracefully.


5. Advanced Routing with go_router

5.1 Setting Up go_router

go_router is a powerful package for advanced routing. Add it to pubspec.yaml:

dependencies:
  go_router: ^10.0.0

5.2 Configuring Routes and Sub-Routes

Configure routes in MaterialApp.router:

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

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

final GoRouter _router = GoRouter(
  routes: [
    GoRoute(
      path: '/',
      builder: (context, state) => HomeScreen(),
    ),
    GoRoute(
      path: '/details',
      builder: (context, state) => DetailsScreen(),
    ),
  ],
);

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: _router,
    );
  }
}

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Home')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            context.go('/details');
          },
          child: Text('Go to Details'),
        ),
      ),
    );
  }
}

class DetailsScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Details')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            context.go('/');
          },
          child: Text('Go Back'),
        ),
      ),
    );
  }
}

5.3 Handling Query Parameters

Pass data via query parameters:

context.go('/details?item=Phone');

Retrieve in DetailsScreen:

class DetailsScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final item = GoRouterState.of(context).queryParameters['item'] ?? 'Unknown';
    return Scaffold(
      appBar: AppBar(title: Text('Details')),
      body: Center(child: Text('Item: $item')),
    );
  }
}

5.4 Real-Life Example: An E-Commerce App

An e-commerce app with product listing and details:

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

void main() {
  runApp(ECommerceApp());
}

final GoRouter _router = GoRouter(
  routes: [
    GoRoute(
      path: '/',
      builder: (context, state) => ProductListScreen(),
    ),
    GoRoute(
      path: '/product/:id',
      builder: (context, state) {
        final id = state.pathParameters['id']!;
        return ProductDetailScreen(id: id);
      },
    ),
  ],
);

class ECommerceApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: _router,
    );
  }
}

class ProductListScreen extends StatelessWidget {
  final List<Map<String, String>> products = [
    {'id': '1', 'name': 'Laptop'},
    {'id': '2', 'name': 'Phone'},
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Products')),
      body: ListView.builder(
        itemCount: products.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(products[index]['name']!),
            onTap: () {
              context.go('/product/${products[index]['id']}');
            },
          );
        },
      ),
    );
  }
}

class ProductDetailScreen extends StatelessWidget {
  final String id;

  ProductDetailScreen({required this.id});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Product $id')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            context.go('/');
          },
          child: Text('Back to Products'),
        ),
      ),
    );
  }
}

Explanation:

  • go_router handles dynamic routes with path parameters (/product/:id).

  • context.go navigates to the product details screen.

Best Practices:

  • Use go_router for large apps with complex routing.

  • Leverage path and query parameters for flexibility.

  • Keep route configurations modular.


6. Handling Deep Links in Flutter Apps

6.1 Understanding Deep Links

Deep links allow users to navigate directly to specific app content from external sources (e.g., a web link). For example, clicking a news article link opens the app's article screen.

6.2 Configuring Deep Links

Add deep link support using go_router:

dependencies:
  go_router: ^10.0.0
  uni_links: ^0.5.1

Configure in android/app/src/main/AndroidManifest.xml:

<activity
    android:name=".MainActivity"
    android:launchMode="singleTop">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <data android:scheme="myapp" android:host="example.com"/>
    </intent-filter>
</activity>

For iOS, update ios/Runner/Info.plist:

<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>myapp</string>
        </array>
    </dict>
</array>

6.3 Handling Deep Links with go_router

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:uni_links/uni_links.dart';
import 'dart:async';

void main() {
  runApp(NewsApp());
}

final GoRouter _router = GoRouter(
  routes: [
    GoRoute(
      path: '/',
      builder: (context, state) => HomeScreen(),
    ),
    GoRoute(
      path: '/article/:id',
      builder: (context, state) {
        final id = state.pathParameters['id']!;
        return ArticleScreen(id: id);
      },
    ),
  ],
  redirect: (context, state) async {
    final uri = await getInitialLink();
    if (uri != null && uri.startsWith('myapp://example.com/article/')) {
      final id = uri.split('/').last;
      return '/article/$id';
    }
    return null;
  },
);

class NewsApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: _router,
    );
  }
}

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('News Home')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            context.go('/article/123');
          },
          child: Text('View Article'),
        ),
      ),
    );
  }
}

class ArticleScreen extends StatelessWidget {
  final String id;

  ArticleScreen({required this.id});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Article $id')),
      body: Center(child: Text('Reading Article $id')),
    );
  }
}

6.4 Real-Life Example: A News App

A deep link like myapp://example.com/article/123 opens the article directly:

// Add to main.dart
StreamSubscription? _sub;

void initUniLinks() {
  _sub = linkStream.listen((String? link) {
    if (link != null && link.startsWith('myapp://example.com/article/')) {
      final id = link.split('/').last;
      _router.go('/article/$id');
    }
  }, onError: (err) {
    // Handle error
  });
}

Explanation:

  • uni_links listens for deep links.

  • go_router redirects to the appropriate screen.

Best Practices:

  • Test deep links thoroughly on both platforms.

  • Handle invalid links gracefully.

  • Secure deep links to prevent unauthorized access.


7. Practical Exercise: Building a To-Do List App

7.1 Project Setup

Create a new Flutter project and add dependencies:

dependencies:
  flutter:
    sdk: flutter
  go_router: ^10.0.0

7.2 Creating the List View Screen

The list view displays tasks:

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

void main() {
  runApp(TodoApp());
}

final GoRouter _router = GoRouter(
  routes: [
    GoRoute(
      path: '/',
      builder: (context, state) => TodoListScreen(),
    ),
    GoRoute(
      path: '/details/:id',
      builder: (context, state) {
        final id = state.pathParameters['id']!;
        final title = state.queryParameters['title'] ?? '';
        return TodoDetailScreen(id: id, title: title);
      },
    ),
  ],
);

class TodoApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: _router,
    );
  }
}

class TodoListScreen extends StatefulWidget {
  @override
  _TodoListScreenState createState() => _TodoListScreenState();
}

class _TodoListScreenState extends State<TodoListScreen> {
  final List<Map<String, String>> todos = [
    {'id': '1', 'title': 'Buy groceries'},
    {'id': '2', 'title': 'Finish homework'},
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('To-Do List')),
      body: ListView.builder(
        itemCount: todos.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(todos[index]['title']!),
            onTap: () {
              context.go('/details/${todos[index]['id']}?title=${todos[index]['title']}');
            },
          );
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          final result = await Navigator.push(
            context,
            MaterialPageRoute(builder: (context) => AddTodoScreen()),
          );
          if (result != null) {
            setState(() {
              todos.add({'id': '${todos.length + 1}', 'title': result});
            });
          }
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

7.3 Creating the Detail View Screen

The detail view shows task details:

class TodoDetailScreen extends StatelessWidget {
  final String id;
  final String title;

  TodoDetailScreen({required this.id, required this.title});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Task Details')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Task ID: $id'),
            Text('Title: $title'),
            ElevatedButton(
              onPressed: () {
                context.go('/');
              },
              child: Text('Back to List'),
            ),
          ],
        ),
      ),
    );
  }
}

7.4 Implementing Navigation and Data Passing

Add a screen to create new tasks:

class AddTodoScreen extends StatelessWidget {
  final TextEditingController _controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Add Task')),
      body: Padding(
        padding: EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextField(
              controller: _controller,
              decoration: InputDecoration(labelText: 'Task Title'),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                if (_controller.text.isNotEmpty) {
                  Navigator.pop(context, _controller.text);
                }
              },
              child: Text('Save Task'),
            ),
          ],
        ),
      ),
    );
  }
}

7.5 Adding Deep Link Support

Add deep link support for tasks (e.g., myapp://todo.com/details/1):

import 'package:uni_links/uni_links.dart';
import 'dart:async';

// Add to TodoApp
class TodoApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    initUniLinks();
    return MaterialApp.router(
      routerConfig: _router,
    );
  }

  void initUniLinks() {
    linkStream.listen((String? link) {
      if (link != null && link.startsWith('myapp://todo.com/details/')) {
        final id = link.split('/').last;
        _router.go('/details/$id');
      }
    }, onError: (err) {
      // Handle error
    });
  }
}

Explanation:

  • The app uses go_router for navigation.

  • Tasks are displayed in a list, and tapping navigates to the detail screen.

  • Deep links open specific tasks directly.


8. Best Practices for Navigation in Flutter

  • Use Named Routes for Scalability: Centralize route definitions for large apps.

  • Validate Data: Ensure passed data is valid to avoid null errors.

  • Handle Errors: Implement error handling for invalid routes or deep links.

  • Optimize Stack Management: Avoid excessive screen stacking.

  • Test Transitions: Ensure smooth animations across platforms.


9. Pros and Cons of Navigation Approaches

Navigator.push/pop:

  • Pros: Simple, built-in, no dependencies.

  • Cons: Limited for complex apps, manual stack management.

Named Routes:

  • Pros: Organized, reusable, easy to maintain.

  • Cons: Requires upfront route definitions.

go_router:

  • Pros: Advanced features, deep link support, parameter handling.

  • Cons: Dependency overhead, steeper learning curve.


10. Alternatives to go_router

  • auto_route: Offers type-safe routing and code generation.

  • fluro: Lightweight, supports query parameters and wildcards.

  • Navigator 2.0: Flutter's advanced API for custom routing logic.


11. Exception Handling in Navigation

Handle navigation errors to prevent crashes:

try {
  Navigator.pushNamed(context, '/invalid-route');
} catch (e) {
  ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(content: Text('Route not found!')),
  );
}

For go_router, use errorBuilder:

final GoRouter _router = GoRouter(
  routes: [...],
  errorBuilder: (context, state) => ErrorScreen(error: state.error.toString()),
);

12. Conclusion

This module covered Flutter navigation from basic Navigator.push/pop to advanced go_router and deep links. By building a to-do list app, you learned practical, real-world navigation techniques. Apply these skills to create seamless, user-friendly multi-screen apps.

No comments:

Post a Comment

Thanks for your valuable comment...........
Md. Mominul Islam

Post Bottom Ad

Responsive Ads Here