Flutter Navigation and Routing

This section will introduce the navigation and routing mechanisms in Flutter, including page transitions, parameter passing, and named routes.


Navigator Basics

Flutter uses Navigator for page management, implementing page transitions based on a stack structure.

Example: Basic Page Navigation

// Navigate to a new page
Navigator.of(context).push(
  MaterialPageRoute(
    builder: (context) => const DetailPage(),
  ),
);

// Return to the previous page
Navigator.of(context).pop();

// Return with result
Navigator.of(context).pop('Returned data');

// Replace current page (cannot go back)
Navigator.of(context).pushReplacement(
  MaterialPageRoute(
    builder: (context) => const HomePage(),
  ),
);

// Return to root page
Navigator.of(context).popUntil((route) => route.isFirst);

MaterialPageRoute vs CupertinoPageRoute

Example: Page Transition Animations on Different Platforms

// Android style - rises from the bottom
Navigator.of(context).push(
  MaterialPageRoute(
    builder: (context) => const DetailPage(),
  ),
);

// iOS style - slide in from the right
Navigator.of(context).push(
  CupertinoPageRoute(
    builder: (context) => const DetailPage(),
  ),
);

// Custom transition effect
Navigator.of(context).push(
  PageRouteBuilder(
    pageBuilder: (context, animation, secondaryAnimation) {
      return const DetailPage();
    },
    transitionsBuilder: (context, animation, secondaryAnimation, child) {
      // Fade in/out effect
      return FadeTransition(
        opacity: animation,
        child: child,
      );
    },
    transitionDuration: const Duration(milliseconds: 300),
  ),
);

Page Parameter Passing

< h2 class="example">Example: Passing parameters to a new page
// Jump to detail page and pass parameters
Navigator.of(context).push(
  MaterialPageRoute(
    builder: (context) => ProductDetailPage(productId: 123),
  ),
);

// Detail page receives parameters
class ProductDetailPage extends StatelessWidget {
  final int productId;

  const ProductDetailPage({
    super.key,
    required this.productId,
  });

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

// Pass multiple parameters
class UserProfilePage extends StatelessWidget {
  final String name;
  final int age;

  const UserProfilePage({
    super.key,
    required this.name,
    required this.age,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text($name's homepage)),
      body: Center(child: Text('Age: $age')),
    );
  }
}

// Jump
Navigator.of(context).push(
  MaterialPageRoute(
    builder: (context) => const UserProfilePage(
      name: 'Zhang San',
      age: 25,
    ),
  ),
);

Named route

Using named routes can simplify page transition configuration.

Example: Named Route Configuration

void main() {
  runApp(
    MaterialApp(
      // Define routing table
      initialRoute: '/',
      routes: {
        '/': (context) => const HomePage(),
        '/detail': (context) => const DetailPage(),
        '/user': (context) => const UserPage(),
        '/settings': (context) => const SettingsPage(),
      },
    ),
  );
}

// Jump
Navigator.pushNamed(context, '/detail');

// Navigate with parameters
Navigator.pushNamed(context, '/user', arguments: {'name': 'Zhang San', 'age': 25});

// Get parameters on the target page
class DetailPage extends StatelessWidget {
  const DetailPage({super.key});

  @override
  Widget build(BuildContext context) {
    // Get the passed parameters
    final args = ModalRoute.of(context)?.settings.arguments as Map?;

    return Scaffold(
      appBar: AppBar(title: const Text('Detail Page')),
      body: Center(
        child: Text(Arguments: $args),
      ),
    );
  }
}

Another Way to Pass Values in Routing

Example: onGenerateRoute

MaterialApp(
  onGenerateRoute: (settings) {
    // Return different pages based on the route name
    switch (settings.name) {
      case '/':
        return MaterialPageRoute(
          builder: (_) => const HomePage(),
        );
      case '/detail':
        // Retrieve parameters from arguments
        final args = settings.arguments as Map<String, dynamic>?;
        return MaterialPageRoute(
          builder: (_) => DetailPage(
            id: args?['id'] ?? 0,
            title: args?['title'] ?? '',
          ),
        );
      case '/product':
        final productId = settings.name?.split('/').last;
        return MaterialPageRoute(
          builder: (_) => ProductPage(id: productId ?? ''),
        );
      default:
        return MaterialPageRoute(
          builder: (_) => const NotFoundPage(),
        );
    }
  },
)

For simple applications, basic Navigator.push is sufficient; for medium to large applications, it is recommended to use named routes or routing management libraries to centrally manage pages.

other extensions