In this design mode, the page route jumps

I’m not using the context and I’m not using any routing plug-ins.

Definition and composition of a template method pattern

The template method pattern is a very simple pattern that can be implemented using inheritance alone.

The template method pattern consists of two parts, the first part is the abstract parent class, the second part is the concrete implementation child class. The algorithm framework of a subclass is usually encapsulated in an abstract superclass, including the implementation of some common methods and the execution order of all methods in the subclass. By inheriting this abstract class, subclasses also inherit the entire algorithm structure and can choose to override the methods of the parent class.

Let’s say we have some parallel subclasses, some of the same behaviors, some of the different behaviors. If the same and different behaviors are mixed in the implementation of each subclass, it means that the same behaviors are repeated in each subclass.

But in fact, the same behavior can be moved to another single place, and the template method pattern was created to solve this problem. In the template method pattern, the same parts of the subclass implementation are moved up into the parent class, leaving the different parts to be implemented by the subclass. This is also a good example of the idea of generalization.

—- from Javascript Design Patterns and Development Practices

How to do that?

First of all, each page has a route to jump method, jump time to set the route name. They may also perform a POP to remove the current page. And then to each page of the user’s entry to leave the buried point report.

The same is true of the jump and pop methods of routing, as well as the user behavior buried points. The difference is setting the route name, which must be subclassed.

Based on this, we started creating an abstract class called BasePage

/// BasePage is an abstract page from which all pages should inherit
/// [ResultType] is the data type returned when the page pops.
abstract class BasePage<ResultType> extends StatefulWidget {
  /// Context Is the key to redirect routes and the global navigation key
  static final GlobalKey<NavigatorState> navigatorKey = GlobalKey();

  /// The name of the Settings page that needs to be subclassed
  String get pageName;

  /// The builder PageRoute
  Widget _pageBuilder(BuildContext context) {
    return this;
  }

  /// Create a PageRoute
  Route<ResultType> createPageRoute(WidgetBuilder builder, RouteSettings settings) {
    return MaterialPageRoute(
      settings: settings,
      builder: builder,
    );
  }

  /// Get Route Settings
  RouteSettings get settings => RouteSettings(name: pageName);

  /// Hop routing
  Future<ResultType> active({bool replace}) {
    var page = createPageRoute(_pageBuilder, settings);
    assert(page.settings ! =null); // The createPageRoute function must set Settings
    assert(page.settings.name ! =null); // Settings must contain name.
    if (replace == true) {
      return navigatorKey.currentState.pushReplacement(page);
    } else {
      returnnavigatorKey.currentState.push(page); }}}Copy the code

Very simple, it can only be a simple jump at the moment, but in the future it is very convenient to extend the active() jump function to make the jump more flexible. The child pages that inherit from it gain the corresponding capabilities. The active function here is the template method because it encapsulates the call order and jump logic.

Okay, now you need to register your navigatorKey with the MaterialApp.

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: BasePage.navigatorKey,
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Template Method Design Pattern',),); }}Copy the code

oh! There’s also BasePageState. StatefulWidget and State always come in pairs, right? We have the abstract class BasePage that inherits from the StatefulWidget, but it does not provide initState and Dispose for user behavior burying points. So let’s create another abstract class, BasePageState

/// State that holds the BasePage instance
abstract class BasePageState<T extends BasePage> extends State<T> {
  
  @mustCallSuper
  @override
  void initState() {
    print('[BasePageState]: records user open${widget.pageName}Page ');
    super.initState();
  }

  @mustCallSuper
  @override
  void dispose() {
    print('[BasePageState]: records the user leaving${widget.pageName}Page ');
    super.dispose();
  }

  /// Encapsulated pop.
  bool pop<T extends Object>([T result]) {
    returnNavigator.pop<T>(context, result); }}Copy the code

At this point, we have written a basic page template.

Create the first page and have it inherit from the template.

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:page_route/base_page.dart';

class PageOne extends BasePage<String> {
  final String title;

  PageOne(this.title);

  @override
  _PageOneState createState() => _PageOneState();

  @override
  String get pageName => 'PageOne';
}

class _PageOneState extends BasePageState<PageOne> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Container(
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text('Current page is${widget.title}'),
              RaisedButton(
                onPressed: () => pop('Page one is over'),
                child: Text('Return result'() [() (() (() (() (() () (() () () () ( }@override
  void initState() {
    print('${widget.pageName}Start getting data ');
    super.initState();
  }

  @override
  void dispose() {
    print('Destroy unwanted objects');
    super.dispose(); }}Copy the code

See, this way, creating a page isn’t much different from creating a StatefulWidget, and you get route startup capability. Allows us to launch a page anytime, anywhere. Pop the current page without writing a long string of navigator. pop

(context, result).

Personalize the route jump animation

If we want to add some jump animations to a page, we simply override the createPageRoute method of the rewrite template on the page.

Create a second page, PageTwo, and fade out

import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:page_route/base_page.dart'; class PageTwo extends BasePage { @override _PageTwoState createState() => _PageTwoState(); @override String get pageName => 'PageTwo'; @override Route createPageRoute(builder, RouteSettings settings) { return PageRouteBuilder( transitionDuration: Duration(milliseconds: 500), // animation time: 500ms Settings: Settings, // Must load Settings pageBuilder: (BuildContext Context, Animation Animation, Animation secondaryAnimation) {return new FadeTransition(// Use fade in, Opacity: animation, child: Builder (context), // route B); }); } } class _PageTwoState extends BasePageState<PageTwo> { @override Widget build(BuildContext context) { return Scaffold( AppBar: appBar (title: Text(' rewrite createPageRoute'),), body: Container(child: Center(child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[Text(' the current page's route animation is implemented by overwriting createPageRoute '), RaisedButton(onPressed: () => pop(' Page two is finished '), child: Text(' return result '),)],),),),); }}Copy the code

As you can see, as long as we follow the single responsibility principle, we can improve the extensibility of the application to some extent. Opening PageTwo is as simple as ever.

void goPageTwo() {
  PageTwo().active();
}
Copy the code

Create a page quickly

As we know, ides provide some live templates. You can quickly create a StatefulWidget by typing stful. We can write a page shortcut template modeled after Stful. Let’s start with Stful.

Ok, you have learned to create shortcut templates, so you create a page.

When creating a new shortcut template, be sure to set the template language.

The code in the screenshot is not complete, here is the full version:

import 'package:flutter/material.dart';
import 'package:page_route/base_page.dart';

class $PAGE_NAME$ extends BasePage {
  @override
  _$PAGE_NAME$State createState() => _$PAGE_NAME$State();

  @override
  String get pageName => '$PAGE_NAME$';
}

class _$PAGE_NAME$State extends BasePageStateThe < $PAGE_NAMEThe $>{
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('$END$'), ), body: Container(), ); }}Copy the code

Just write page like stful and you can quickly create a page.