DEV Community

Aadarsh Kunwar
Aadarsh Kunwar

Posted on

Flutter PageView or Navigator

In Flutter, there are two common ways to navigate between pages or views: using the Navigator and implementing a page view with PageView.

  1. Using Navigator for Navigation Between Pages The Navigator is the primary way to manage a stack of routes, allowing you to push and pop routes (pages) to navigate between them.
import 'package:flutter/material.dart';

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

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

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

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Second Page')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: Text('Go back to Home Page'),
        ),
      ),
   );
  }
}
Enter fullscreen mode Exit fullscreen mode
  1. Using PageView for Swiping Between Pages PageView is useful for scenarios where you want to allow users to swipe between pages, similar to a carousel or a stepper.
import 'package:flutter/material.dart';

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

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

class PageViewExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('PageView Example')),
      body: PageView(
        children: <Widget>[
          Container(
            color: Colors.red,
            child: Center(child: Text('Page 1', style: TextStyle(fontSize: 24))),
          ),
          Container(
            color: Colors.green,
            child: Center(child: Text('Page 2', style: TextStyle(fontSize: 24))),
          ),
          Container(
            color: Colors.blue,
            child: Center(child: Text('Page 3', style: TextStyle(fontSize: 24))),
          ),
        ],
      ),
    );
  }
}

Enter fullscreen mode Exit fullscreen mode

Top comments (2)

Collapse
 
anshuman_mishra_v36 profile image
Anshuman Mishra

Nice, this should be helpful for beginners still trying to figure stuff out.
One could say its better to use navigator for pages handling authentication.
Also could you touch on the behavior of navigators and its types legacy or otherwise in the next post?
I will be waiting, Have a nice day.

Collapse
 
aadarshk7 profile image
Aadarsh Kunwar

In Flutter, the Navigator is a key component that manages a stack of routes (or pages) for navigation. Understanding how the Navigator behaves and the different types of navigators is essential for managing the navigation flow in your app.

  1. Navigator Behavior The Navigator in Flutter is responsible for managing routes, where each route corresponds to a screen or a page. It uses a stack data structure, meaning that routes can be pushed onto the stack (to navigate to a new screen) and popped off the stack (to go back to the previous screen).
  • Push: Adds a route to the top of the stack. This is commonly used when you want to navigate to a new screen.
Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => NewScreen()),
);
Enter fullscreen mode Exit fullscreen mode
  • Pop: Removes the topmost route from the stack, returning to the previous screen.
Navigator.pop(context);
Enter fullscreen mode Exit fullscreen mode
  • PushReplacement: Replaces the current route with a new one. This is useful when you don't want the user to be able to navigate back to the previous screen.
Navigator.pushReplacement(
  context,
  MaterialPageRoute(builder: (context) => NewScreen()),
);
Enter fullscreen mode Exit fullscreen mode
  • PushAndRemoveUntil: Pushes a new route and removes all the previous routes until the specified condition is met.
Navigator.pushAndRemoveUntil(
  context,
  MaterialPageRoute(builder: (context) => NewScreen()),
  (Route<dynamic> route) => false,
);
Enter fullscreen mode Exit fullscreen mode
  • CanPop: Checks if there are any routes left to pop.
CanPop: Checks if there are any routes left to pop
Enter fullscreen mode Exit fullscreen mode
  1. . Types of Navigators (Legacy & Declarative) Flutter primarily offers two navigation styles: Imperative Navigation (Legacy) and Declarative Navigation.

Imperative Navigation (Legacy)
This is the traditional way of navigation, where the developer manually controls the navigation stack using Navigator methods like push, pop, etc. This approach is more common and straightforward, especially for simple apps.

  • Route Settings: You define routes in MaterialApp or CupertinoApp using the routes parameter.
MaterialApp(
  routes: {
    '/': (context) => HomeScreen(),
    '/second': (context) => SecondScreen(),
  },
);
Enter fullscreen mode Exit fullscreen mode
  • Named Routes: Allows navigation by route names.
Navigator.pushNamed(context, '/second');
Enter fullscreen mode Exit fullscreen mode
  • Custom Route Transitions: You can customize transitions by overriding the PageRoute class or using PageRouteBuilder.
Navigator.push(
  context,
  PageRouteBuilder(
    pageBuilder: (context, animation, secondaryAnimation) => SecondScreen(),
    transitionsBuilder: (context, animation, secondaryAnimation, child) {
      var begin = Offset(0.0, 1.0);
      var end = Offset.zero;
      var curve = Curves.ease;

      var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));

      return SlideTransition(
        position: animation.drive(tween),
        child: child,
      );
    },
  ),
);
Enter fullscreen mode Exit fullscreen mode

Declarative Navigation (Navigator 2.0)
Introduced in Flutter 1.22, declarative navigation offers a more reactive and flexible way of managing navigation, similar to how UI is managed in a declarative style. This approach is more complex but provides finer control over the navigation stack, making it suitable for complex apps.

  • Router: The core of declarative navigation, where you define the app's routing logic declaratively.
MaterialApp.router(
  routerDelegate: MyRouterDelegate(),
  routeInformationParser: MyRouteInformationParser(),
);
Enter fullscreen mode Exit fullscreen mode
  • Page API: Unlike the legacy Route API, the declarative approach uses Page objects to represent pages.
List<Page> buildPages() {
  return [
    MaterialPage(child: HomeScreen(), key: ValueKey('Home')),
    if (showDetails) MaterialPage(child: DetailsScreen(), key: ValueKey('Details')),
  ];
}
Enter fullscreen mode Exit fullscreen mode
  • RouterDelegate and RouteInformationParser: These classes handle the navigation logic and parse route information.
class MyRouterDelegate extends RouterDelegate with ChangeNotifier {
  @override
  Widget build(BuildContext context) {
    return Navigator(
      pages: buildPages(),
      onPopPage: (route, result) {
        if (!route.didPop(result)) {
          return false;
        }
        return true;
      },
    );
  }

  // Other methods...
}
Enter fullscreen mode Exit fullscreen mode
  1. Choosing Between Legacy and Declarative Navigation Legacy Navigator (Imperative): Best for small to medium apps with simple navigation needs. Easier to implement and understand.

Declarative Navigator: Ideal for large, complex apps where navigation needs to be tightly integrated with the app's state. It provides more flexibility and better control over the navigation stack.

Summary
Imperative Navigation (Legacy): Direct, explicit control over navigation with Navigator methods.
Declarative Navigation: Reactive, flexible, and integrated with app state management, suitable for more complex scenarios.

Depending on your app's complexity and requirements, you can choose the appropriate navigation style that fits your needs.