当前位置:网站首页>Flutter series -flutter route management

Flutter series -flutter route management

2022-06-22 19:27:00 Liuyichu

First understand the concept of routing

The concept of routing has a long history , Include network routing 、 Back end routing , Now widely popular Front-end routing . No matter how the concept of routing is applied , At its core is a Route mapping table . such as : name detail Mapping to DetailPage Page etc. . With this mapping table , We can easily complete the routing forwarding according to the name ( What is displayed in the front end is page Jump )

route (Route) In mobile development, it usually refers to page (Page), This one web Single page application in development Route The conceptual meaning is the same ,Route stay Android Usually refers to a Activity, stay iOS Middle refers to a ViewController. So called route management , Is how to manage the jump between pages , It can also be called navigation management .Flutter Routing management in is similar to native development , Whether it's Android still iOS, Navigation management will maintain a routing stack , Route to stack (push) Operation corresponds to opening a new page , Route out of the stack (pop) Operation corresponding page close operation , Routing management mainly refers to how to manage the routing stack .

One . Routing management

1.1.Route

Route: A page wants to be managed by routing , It has to be packaged as a Route

The official statement is very clear :An abstraction for an entry managed by a Navigator.

however Route Is an abstract class , So it cannot be instantiated .

1.2.MaterialPageRoute

in fact MaterialPageRoute Not at all Route The direct subclass of :

MaterialPageRoute There are different performances on different platforms :

Yes Android platform , Opening a page will slide from the bottom of the screen to the top of the screen , Slide from top to bottom when closing the page ; Yes iOS platform , Opening a page slides from the right side of the screen to the left side of the screen , Slide from left to right when closing the page

MaterialPageRoute The meaning of each parameter of the constructor :

 MaterialPageRoute({
    WidgetBuilder builder,
    RouteSettings settings,
    bool maintainState = true,
    bool fullscreenDialog = false,
  })

builder: It's a WidgetBuilder Type of callback function , Its function is to build the specific content of the routing page , The return value is one widget. We usually implement this callback , Returns an instance of a new route .
settings: Contains configuration information for routes , Such as route name 、 Initial route or not ( home page ).
maintainState: By default , When a new route is pushed , The original route will still be saved in memory , If you want to release all the resources occupied by the route when it is useless , You can set maintainState by false.
fullscreenDialog: Indicates whether the new routing page is a full screen modal dialog , stay iOS in , If fullscreenDialog by true, The new page will slide in from the bottom of the screen ( Not horizontally ).

MaterialPageRoute -> PageRoute -> ModalRoute -> TransitionRoute -> OverlayRoute -> Route

1.3.Navigator

Navigator It is a component of route management , It provides ways to open and exit routing pages .Navigator Manage the active route set through a stack . Usually the current screen shows the route on the top of the stack .Navigator Provides a series of methods to manage the routing stack

The official statement is also very clear :A widget that manages a set of child widgets with a stack discipline.

Then we need to manually create one during development Navigator Do you ? It doesn't need to , Used in our development MaterialApp、CupertinoApp、WidgetsApp They have inserts by default Navigator Of . therefore , When we need to , Just use it directly

Navigator.of(context)

Common methods :

//  Routing jump : Pass in a routing object ( The return value is one Future object , To receive a new route out of the stack ( Close now ) Data returned at .)
Future<T> push<T extends Object>(Route<T> route)

//  Routing jump : Pass in a name ( Named route )
Future<T> pushNamed<T extends Object>(
  String routeName, {
    Object arguments,
  })

//  Routing returns : You can pass in a parameter ,result Data returned to the previous page when the page is closed .
bool pop<T extends Object>([ T result ])

Navigator The first parameter in the class is context The static methods of the Navigator Instance method of

Navigator.push(BuildContext context, Route route)

Equivalent to

Navigator.of(context).push(Route route)

1.4. Routing values

Be similar to Android In development activity Used between Intent Pass value .

Example :

We create a TipRoute route , It accepts a String Parameters , And display it on the page , in addition TipRoute Let's add a “ return ” Button , Click to return to the previous route with a return parameter , Let's take a look at the implementation code .

class TipRoute extends StatelessWidget {
  TipRoute({
    Key key,
    @required this.text,  //  Receive one text Parameters 
  }) : super(key: key);
  final String text;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(" Tips "),
      ),
      body: Padding(
        padding: EdgeInsets.all(18),
        child: Center(
          child: Column(
            children: <Widget>[
              Text(text),
              RaisedButton(
                onPressed: () => Navigator.pop(context, " I'm the return value "),
                child: Text(" return "),
              )
            ],
          ),
        ),
      ),
    );
  }
}

Here's how to open a new route TipRoute Code for :

class RouterTestRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: RaisedButton(
        onPressed: () async {
          //  open `TipRoute`, And wait for the return result 
          var result = await Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) {
                return TipRoute(
                  //  Routing parameters 
                  text: " I'm a hint xxxx",
                );
              },
            ),
          );
          // Output `TipRoute` Routing returns results 
          print(" Route return value : $result");
        },
        child: Text(" Open the prompt page "),
      ),
    );
  }
}

Run the above code , Click on RouterTestRoute page “ Open the prompt page ” Button , Will open TipRoute page . Insert picture description here

“ I'm a hint xxxx” It's through TipRoute Of text Parameter to the new routing page . We can wait Navigator.push(…) Back to Future To get the return data of the new route .

stay TipRoute There are two ways to go back to the previous page ; In the first way, click the navigation bar to return to the arrow , The second way is to click... On the page “ return ” Button . The difference between the two return methods is that the former does not return data to the previous route , The latter will . The following is after clicking the return button in the page and the return arrow in the navigation bar respectively ,RouterTestRoute Page print Method in the console :

I/flutter (27896):  Route return value :  I'm the return value 
I/flutter (27896):  Route return value : null

The above is about the value transmission mode of unnamed routing , The way named routes pass values is different .

1.5 Named route

We can create a new Route, Use Navigator To navigate to a new page , But if you need to navigate to the same page in many places in the application ( For example, in development , home page 、 recommend 、 The classification page may jump to the details page ), Then there will be a lot of duplicate code .

under these circumstances , We can use named routes (Named Route), So-called “ Named route ” That is, routes with names , We can give the route a name first , Then you can open a new route directly through the route name , This brings a kind of intuition for route management 、 In a simple way , This is generally recommended .

Routing table

To use a named route , We must first provide and register a routing table (routing table), So that the application knows which name corresponds to which routing component . In fact, registering a routing table is to name a route , The routing table is defined as follows :

Map<String, WidgetBuilder> routes;

It's a Map,key For the name of the route , It's a string ;value It's a builder Callback function , Used to generate the corresponding route widget. When we open a new route by routing name , The application will find the corresponding... In the routing table according to the routing name WidgetBuilder Callback function , Then call the callback function to generate the route. widget And back to .

Register routing table
Where are named routes managed ? Can be placed in MaterialApp Of initialRoute and routes in

MaterialApp(
  title: 'Flutter Demo',
  theme: ThemeData(
    primarySwatch: Colors.blue,
  ),
  // Register routing table 
  routes:{
   "new_page":(context) => NewRoute(),
    ... //  Omit other route registration information 
  } ,
  home: MyHomePage(title: 'Flutter Demo Home Page'),
);

routes: Define the mapping relationship between name and route , The type is Map<String, WidgetBuilder>

initialRoute: Set which route the application starts from , This property is set , You don't need to set it up again home The attribute is
as follows :

MaterialApp(
  title: 'Flutter Demo',
  initialRoute:"/", // be known as "/" Routing as an application home( home page )
  theme: ThemeData(
    primarySwatch: Colors.blue,
  ),
  // Register routing table 
  routes:{
   "new_page":(context) => NewRoute(),
   "/":(context) => MyHomePage(title: 'Flutter Demo Home Page'), // Register home route 
  } 
);

Open a new routing page by routing name

Future pushNamed(BuildContext context, String routeName,{Object arguments})

Example :

onPressed: () {
  Navigator.pushNamed(context, "new_page");
  //Navigator.push(context,
  //  MaterialPageRoute(builder: (context) {
  //  return NewRoute();
  //}));  
},

In development , To make each page correspond to routeName Unified , We usually define a routing constant in each page to use , for example :

class HomePage extends StatefulWidget {
  static const String routeName = "/home";
}

class DetailPage extends StatelessWidget {
  static const String routeName = "/detail";
}

modify MaterialApp in routes Of key

initialRoute: HomePage.routeName,
routes: {
  HomePage.routeName: (context) => HomePage(),
  DetailPage.routeName: (context) => DetailPage()
},

1.6. Named route parameter passing

Let's register a route first :

routes:{
   "new_page":(context) => EchoRoute(),
  } ,

Pass on route page RouteSetting Object get route parameters :

class EchoRoute extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    // Get route parameters   
    var args=ModalRoute.of(context).settings.arguments;
    //... Omit irrelevant code 
  }
}

Pass parameters on route open

Navigator.of(context).pushNamed("new_page", arguments: "hi");

To obtain parameters : stay build In the method ModalRoute.of(context) You can get the passed parameters

Widget build(BuildContext context) {
    // 1. get data 
    final args= ModalRoute.of(context).settings.arguments;
  }

1.7. adapter

Suppose we also want to transfer the above routing parameters to TipRoute The routing page is registered in the routing table , So that it can also be opened by route name . however , because TipRoute Accept one text Parameters , How we don't change TipRoute Source code to adapt to this situation ? It's very simple :

MaterialApp(
  ... // Omit irrelevant code 
  routes: {
   "tip2": (context){
     return TipRoute(text: ModalRoute.of(context).settings.arguments);
   },
 }, 
);

Two 、 Routing hook

Suppose we want to develop an e-commerce APP, When users don't log in, they can look at the store 、 Goods and other information , But transactions 、 The shopping cart 、 The user's personal information and other pages can only be viewed after login . In order to achieve the above functions , We need to determine the user login status before opening each routing page ! It will be very troublesome if we need to judge every time we turn on the route , Is there any better way ? The answer is yes. !

MaterialApp There is one onGenerateRoute attribute , It may be called when a named route is turned on , It's possible , Because when you call Navigator.pushNamed(…) When opening named routes , If the specified route name is already registered in the routing table , In the routing table builder Function to generate routing components ; If there is no registration in the routing table , Will call onGenerateRoute To generate a route .onGenerateRoute The callback signature is as follows :

Route<dynamic> Function(RouteSettings settings)

With onGenerateRoute Callback , It's very easy to realize the above function of controlling page permissions : We give up using routing tables , Instead, provide a onGenerateRoute Callback , Then the unified permission control is carried out in the callback , Such as :

MaterialApp(
  ... // Omit irrelevant code 
  onGenerateRoute:(RouteSettings settings){
      return MaterialPageRoute(builder: (context){
           String routeName = settings.name;
       //  If the routing page to be accessed needs to be logged in , But I'm not currently logged in , Then return to the login page directly ,
       //  Guide users to log in ; In other cases, turn on the route normally .
     }
   );
  }
);

Be careful ,onGenerateRoute Only for named routes .

3、 ... and 、onUnknownRoute

If a route name we open does not exist at all , At this time, we want to jump to a unified error page . Like the following abc There is no corresponding page , If there is no special treatment , that Flutter Will report a mistake .

RaisedButton(
  child: Text(" Open the unknown page "),
  onPressed: () {
    Navigator.of(context).pushNamed("/abc");
  },
)

We can create an error page :

class UnknownPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(" Error page "),
      ),
      body: Container(
        child: Center(
          child: Text(" Page Jump error "),
        ),
      ),
    );
  }
}

And set up onUnknownRoute

onUnknownRoute: (settings) {
  return MaterialPageRoute(
    builder: (ctx) {
      return UnknownPage();
    }
  );
},

Four 、 ending

Because named route is only an optional route management method , In actual development , I will hesitate which route management method to use . Share according to Daniel's online experience , It is recommended that the management method of named routes be used uniformly , This will bring the following benefits :

1. Semantics is more explicit .

2. Better code maintenance ; If you use anonymous routing , Must be called on Navigator.push Create a new routing page , It doesn't just take import New routing page dart file , And the code will be very fragmented .

3. Can pass onGenerateRoute Do some logical jump processing for global routing .
原网站

版权声明
本文为[Liuyichu]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/173/202206221754259963.html