Simplify Navigation in Flutter with AutoRoute

Simplify Navigation in Flutter with AutoRoute

Beginner's guide to navigation using auto_route

Navigation is a crucial aspect of mobile app development, enabling users to move between different screens seamlessly. In Flutter, the navigation process can sometimes become complex, especially as your app grows. To address this challenge, developers often turn to routing solutions that make navigation more manageable and maintainable. One such solution is auto_route.

Getting Started with AutoRoute

Setting Up Your Flutter Project

To begin using auto_route, start by creating a new Flutter project using flutter create new_project.

Open your pubspec.yaml file and add the following dependencies:

dependencies:
  auto_route: ^7.8.4

dev_dependencies:
  auto_route_generator: 7.3.2
  build_runner:

After adding the dependencies, run flutter pub get to install them.

Project Folder Structure

Next, organize your project by creating folders inside the lib directory. Create a screens folder and a route_config folder. Inside the route folder, create a file called app_route.dart. Within the screens folder, create a file called control_screen.dart. Additionally, create a new folder inside screens called sub_screens. Inside this folder, create three files: screen1.dart, screen2.dart, and screen3.dart.

Your project structure should now look like this:

/lib
  /screens
    /sub_screens
      screen1.dart
      screen2.dart
      screen3.dart
    control_screen.dart
  /route_config
    app_route.dart
 main.dart

Defining Routes with AutoRoute

Now, let's define the routes in app_route.dart.

import 'package:auto_route/annotations.dart';
import 'package:auto_route/auto_route.dart';
import 'app_route.gr.dart'; // from the generated file

@AutoRouterConfig()
class AppRouter extends $AppRouter {
  @override
  List<AutoRoute> get routes => [
        AutoRoute(path: '/', page: Controlscreen.page),
        AutoRoute(path: '/screen1', page: Screen1.page),
        AutoRoute(path: '/screen2', page: Screen2.page),
        AutoRoute(path: '/screen3', page: Screen3.page),
      ];
}

Generating Routes

With the routes defined, you need to generate them using the build_runner command:

if you want the generator to run one time run:

flutter packages pub run build_runner build

This command will generate the necessary files for auto_route to handle the navigation or run flutter packages pub run build_runner watch if you want to generate them while making changes.

Running this will create a new file inside the route_config folder called app_route_gr.dart.

generated app_route_gr.dart:

// GENERATED CODE - DO NOT MODIFY BY HAND

// **************************************************************************
// AutoRouterGenerator
// **************************************************************************

// ignore_for_file: type=lint
// coverage:ignore-file

// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:auto_route/auto_route.dart' as _i5;
import 'package:get_it_auto_router_go_router/auto_router/control_screen.dart'
    as _i1;
import 'package:get_it_auto_router_go_router/auto_router/screens/screen1.dart'
    as _i2;
import 'package:get_it_auto_router_go_router/auto_router/screens/screen2.dart'
    as _i3;
import 'package:get_it_auto_router_go_router/auto_router/screens/screen3.dart'
    as _i4;

abstract class $AppRouter extends _i5.RootStackRouter {
  $AppRouter({super.navigatorKey});

  @override
  final Map<String, _i5.PageFactory> pagesMap = {
    Controlscreen.name: (routeData) {
      return _i5.AutoRoutePage<dynamic>(
        routeData: routeData,
        child: const _i1.ControlScreen(),
      );
    },
    Screen1.name: (routeData) {
      return _i5.AutoRoutePage<dynamic>(
        routeData: routeData,
        child: const _i2.Screen1(),
      );
    },
    Screen2.name: (routeData) {
      return _i5.AutoRoutePage<dynamic>(
        routeData: routeData,
        child: const _i3.Screen2(),
      );
    },
    Screen3.name: (routeData) {
      return _i5.AutoRoutePage<dynamic>(
        routeData: routeData,
        child: const _i4.Screen3(),
      );
    },
  };
}

/// generated route for
/// [_i1.ControlScreen]
class Controlscreen extends _i5.PageRouteInfo<void> {
  const Controlscreen({List<_i5.PageRouteInfo>? children})
      : super(
          Controlscreen.name,
          initialChildren: children,
        );

  static const String name = 'Controlscreen';

  static const _i5.PageInfo<void> page = _i5.PageInfo<void>(name);
}

/// generated route for
/// [_i2.Screen1]
class Screen1 extends _i5.PageRouteInfo<void> {
  const Screen1({List<_i5.PageRouteInfo>? children})
      : super(
          Screen1.name,
          initialChildren: children,
        );

  static const String name = 'Screen1';

  static const _i5.PageInfo<void> page = _i5.PageInfo<void>(name);
}

/// generated route for
/// [_i3.Screen2]
class Screen2 extends _i5.PageRouteInfo<void> {
  const Screen2({List<_i5.PageRouteInfo>? children})
      : super(
          Screen2.name,
          initialChildren: children,
        );

  static const String name = 'Screen2';

  static const _i5.PageInfo<void> page = _i5.PageInfo<void>(name);
}

/// generated route for
/// [_i4.Screen3]
class Screen3 extends _i5.PageRouteInfo<void> {
  const Screen3({List<_i5.PageRouteInfo>? children})
      : super(
          Screen3.name,
          initialChildren: children,
        );

  static const String name = 'Screen3';

  static const _i5.PageInfo<void> page = _i5.PageInfo<void>(name);
}

Utilizing auto_route in main.dart:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'auto_router/route/app_route.dart';

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

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

  @override
  Widget build(BuildContext context) {
    SystemChrome.setSystemUIOverlayStyle(
      const SystemUiOverlayStyle(
        statusBarColor: Colors.transparent,
        statusBarIconBrightness: Brightness.dark,
      ),
    );
    final appRouter = AppRouter();

    // auto router
    return MaterialApp.router(
      title: 'Flutter AutoRouter',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.brown),
        useMaterial3: true,
      ),
      routerConfig: appRouter.config(),
    );
  }
}

Codes for Screens

screen1.dart:

import 'package:auto_route/annotations.dart';
import 'package:flutter/material.dart';

@RoutePage(name: 'screen1')

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Screen 1'),
      ),
      body: const Center(
        child: Text('Screen 1'),
      ),
    );
  }
}

screen2.dart:

import 'package:auto_route/annotations.dart';
import 'package:flutter/material.dart';

@RoutePage(name: 'screen2')

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Screen 2'),
      ),
      body: const Center(
        child: Text('Screen 2'),
      ),
    );
  }
}

screen3.dart:

import 'package:auto_route/annotations.dart';
import 'package:flutter/material.dart';

@RoutePage(name: 'screen3')

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Screen 3'),
      ),
      body: const Center(
        child: Text('Screen 3'),
      ),
    );
  }
}

Using AutoRoute in Your App

Now that the routes are generated, you can use auto_route in your application. Let's see an example in control_screen.dart:

import 'package:auto_route/annotations.dart';
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:get_it_auto_router_go_router/go_router/config/route_config.dart';

enum Screen {
  screen1,
  screen2,
  screen3,
}

@RoutePage(name: 'controlscreen')
class ControlScreen extends StatelessWidget {
  const ControlScreen({super.key});

  void navigateToScreen({
    required BuildContext context,
    required Screen screen,
  }) {
    switch (screen) {
      case Screen.screen1:
        context.router.pushNamed('/screen1');
        break;

      case Screen.screen2:
        context.router.pushNamed('/screen2');
        break;

      case Screen.screen3:
        context.router.pushNamed('/screen3');
        break;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Control Screen'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () => navigateToScreen(
                context: context,
                screen: Screen.screen1,
              ),
              child: const Text('Navigate to Screen 1'),
            ),
            const SizedBox(height: 10),
            ElevatedButton(
              onPressed: () => navigateToScreen(
                context: context,
                screen: Screen.screen2,
              ),
              child: const Text('Navigate to Screen 2'),
            ),
            const SizedBox(height: 10),
            ElevatedButton(
              onPressed: () => navigateToScreen(
                context: context,
                screen: Screen.screen3,
              ),
              child: const Text('Navigate to Screen 3'),
            ),
          ],
        ),
      ),
    );
  }
}

In this example, we have a simple ControlScreen widget with buttons to navigate to Screen1, Screen2, and Screen3. The context.router.pushNamed() method is used to trigger the navigation.

Conclusion

AutoRoute in Flutter simplifies the process of managing and navigating through screens in your app. With a clean and organized project structure, along with the powerful capabilities of auto_route, you can enhance the development experience and maintainability of your Flutter applications. Streamlining navigation has never been easier with auto_route.

There is more to auto_router and you can find out more by going through its official documentation using: https://pub.dev/packages/auto_route

Did you find this article valuable?

Support Atuoha Anthony by becoming a sponsor. Any amount is appreciated!