Flutter - 路由管理 - 02 - Fluro

_樟清_發表於2019-06-15

Fluro作為 一個Flutter的 企業級的路由框架 ,確實不錯,可以解決多變的需求情況 ,是時候搞一波了。 我看了官方的demo,寫的有點亂(反正我是這樣感覺的,老外的程式碼總是有點抽象),順便擴充套件一下傳參的問題和使用 Fluttercupertino 轉場動畫。寫了一個demo, 地址在:在這裡在這裡,快點我,快快快

本文基於 Fluro 目前版本 1.4.0 pub.dev/packages/fl…

1. 先看下Demo程式碼結構

Flutter - 路由管理 - 02 -  Fluro

2. 基礎使用

1. 導包

Flutter - 路由管理 - 02 -  Fluro

2. 基礎配置

1. application.dart

class Application {
  static Router router;
}
複製程式碼

2. routes.dart

routes.dart檔案中配置路由,這裡需要注意的事首頁一定要用“/”配置

Flutter - 路由管理 - 02 -  Fluro

class Routes {
  static String root = "/";
  static String home = "/home";
  static String demoParams = "/deme_params";
  static String returnParams = "/return_params";
  static String transitionDemo = "/transitionDemo";
  static String transitionCustomDemo = "/transitionCustomDemo";
  static String transitionCupertinoDemo = "/transitionCupertinoDemo";

  static void configureRoutes(Router router) {

    router.notFoundHandler = new Handler(
        handlerFunc: (BuildContext context, Map<String, List<String>> params) {
      print("ROUTE WAS NOT FOUND !!!");
    });
    /// 第一個引數是路由地址,第二個引數是頁面跳轉和傳參,第三個引數是預設的轉場動畫,可以看上圖
    /// 我這邊先不設定預設的轉場動畫,轉場動畫在下面會講,可以在另外一個地方設定(可以看NavigatorUtil類)
    router.define(root, handler: splashHandler);
    router.define(home, handler: homeHandler);
    router.define(demoParams, handler: demoParamHandler);
    router.define(returnParams, handler: returnParamHandler);
    router.define(transitionDemo, handler: transitionDemoHandler);
    router.define(transitionCustomDemo, handler: transitionDemoHandler);
    router.define(transitionCupertinoDemo, handler: transitionDemoHandler);

  }
}
複製程式碼

3. main.dart

void main() {
  // 註冊 fluro routes
  Router router = Router();
  Routes.configureRoutes(router);
  Application.router = router;


  runApp(MyApp());
}
複製程式碼

4. my_app.dart

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Weather App',
      /// 生成路由
      onGenerateRoute: Application.router.generator,
    );
  }
}
複製程式碼

3. 場景一:設定啟動頁 Splash 跳轉到 Home頁面,並且移除 Splash 頁面

只摘取相關程式碼,完整程式碼去 github檢視,在文章最頂部

首先App啟動,先進入 首頁Splash 頁面,然後 倒數計時2秒,再進入home頁面

1. 效果圖

1. 首先先開啟 Splash 頁面

Flutter - 路由管理 - 02 -  Fluro

2. 兩秒後跳轉到 home 頁面

Flutter - 路由管理 - 02 -  Fluro

2. 程式碼

1. routes.dart

/// 這邊設定了首頁,固定寫法 /
static String root = "/";  
/// home 頁面的 路由地址
static String home = "/home";

/// splashHandler 就是頁面跳轉,在route_handlers.dart
router.define(root, handler: splashHandler);
/// homeHandler  home頁面
router.define(home, handler: homeHandler);
複製程式碼

2. route_handlers.dart

/// 跳轉到首頁Splash		
var splashHandler = new Handler(
    handlerFunc: (BuildContext context, Map<String, List<String>> params) {
  return new SplashPag();
});

/// 跳轉到主頁
var homeHandler = new Handler(
    handlerFunc: (BuildContext context, Map<String, List<String>> params) {
  return HomePage();
});
複製程式碼

3. splash_page.dart

class SplashPag extends StatefulWidget {
  @override
  _SplashPagState createState() => _SplashPagState();
}

class _SplashPagState extends State<SplashPag> {

  @override
  void initState() {
//    Future.delayed(Duration(seconds: 5),(){
//      NavigatorUtil.goHomePage(context);
//    });
	/// 2秒後跳轉到主頁面,上面註釋的程式碼也可以做到倒數計時
    Observable.timer(0, Duration(seconds: 2)).listen((_){
      /// 然後看 NavigatorUtil.dart
      NavigatorUtil.goHomePage(context);
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      body: Center(
        child: Container(
          child: Text('我是歡迎頁面'),
        ),
      ),
    );
  }
}
複製程式碼

4. NavigatorUtil.dart

  /// 跳轉到主頁面
  static void goHomePage(BuildContext context) {
    /// Routes.home 路由地址
	/// replace:true 就是將 splash 頁面給移除掉了,這點後退鍵的時候就不會再出現Splash頁面
    Application.router.navigateTo(context, Routes.home, replace: true);
  }
複製程式碼

5. home_page.dart

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    String name = "來自第一個介面測試一下";
    int age = 14;
    double score = 6.4;
    bool sex = true;
    Person person = new Person(name: 'Zeking', age: 18, sex: true);

    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Center(child: Text('這是主頁')),
          RaisedButton(
            child: Text('傳遞引數string ,int,double,bool ,自定義型別'),
            onPressed: () {
              NavigatorUtil.goDemoParamsPage(
                  context, name, age, score, sex, person);
            },
          ),
          RaisedButton(
            child: Text('傳遞引數,接受返回值'),
            onPressed: () {
              NavigatorUtil.goReturnParamsPage(context).then((result) {
                debugPrint('${result.runtimeType}');
                String message  ;
                /// 如果是 自定義的 Person 類
                if (result.runtimeType == Person) {
                  message = result.toJson().toString();
                  debugPrint('${result.toJson().toString()}');
                } else {
                  message = '$result';
                  debugPrint('$result');
                }
                showResultDialog(context, message);
              });
            },
          ),
          RaisedButton(
            child: Text('框架 自帶 轉場動畫 演示'),
            onPressed: () {
              NavigatorUtil.gotransitionDemoPage(context,
                  /// 這邊進行了 String 編碼
                  FluroConvertUtils.fluroCnParamsEncode("框架 自帶 轉場動畫 演示 \n\n\n   "
                      "這邊只展示 inFromLeft ,剩下的自己去嘗試下,\n\n\n   "
                      "架自帶的有 native,nativeModal,inFromLeft,inFromRight,inFromBottom,fadeIn,custom"));
            },
          ),
          RaisedButton(
            child: Text('框架 自定義 轉場動畫 演示'),
            onPressed: () {
              NavigatorUtil.gotransitionCustomDemoPage(context,
                  FluroConvertUtils.fluroCnParamsEncode('框架 自定義 轉場動畫 演示'));
            },
          ),
          RaisedButton(
            child: Text('修改原始碼,新增使用 Flutter 的 cupertino 轉場動畫'),
            onPressed: () {
              NavigatorUtil.gotransitionCupertinoDemoPage(
                  context,
                  FluroConvertUtils.fluroCnParamsEncode(
                      "修改原始碼,新增使用 Flutter 的 cupertino 轉場動畫"));
            },
          ),
        ],
      ),
    );
  }

  /// 顯示一個Dialgo
  void showResultDialog(BuildContext context,String message){
    showDialog(
      context: context,
      builder: (context) {
        return new AlertDialog(
          title: new Text(
            "Hey Hey!",
            style: new TextStyle(
              color: const Color(0xFF00D6F7),
              fontFamily: "Lazer84",
              fontSize: 22.0,
            ),
          ),
          content: new Text("$message"),
          actions: <Widget>[
            new Padding(
              padding: new EdgeInsets.only(bottom: 8.0, right: 8.0),
              child: new FlatButton(
                onPressed: () {
                  Navigator.of(context).pop(true);
                },
                child: new Text("OK"),
              ),
            ),
          ],
        );
      },
    );
  }
}
複製程式碼

4. 場景二:傳參 String,int,double,bool,自定義型別

1. 效果圖

Flutter - 路由管理 - 02 -  Fluro

2. 程式碼

1. 注意點(型別轉換 fluro_convert_util.dart)

Fluro路由地址,只能傳遞String型別(並且不支援中文),所以需要對 中文,int,double,bool,自定義型別進行一個轉換 , 寫了一個 轉換類 fluro_convert_util.dart

import 'dart:convert';

/// fluro 引數編碼解碼工具類
class FluroConvertUtils {
  /// fluro 傳遞中文引數前,先轉換,fluro 不支援中文傳遞
  static String fluroCnParamsEncode(String originalCn) {
    return jsonEncode(Utf8Encoder().convert(originalCn));
  }

  /// fluro 傳遞後取出引數,解析
  static String fluroCnParamsDecode(String encodeCn) {
    var list = List<int>();

    ///字串解碼
    jsonDecode(encodeCn).forEach(list.add);
    String value = Utf8Decoder().convert(list);
    return value;
  }

  /// string 轉為 int
  static int string2int(String str) {
    return int.parse(str);
  }

  /// string 轉為 double
  static double string2double(String str) {
    return double.parse(str);
  }

  /// string 轉為 bool
  static bool string2bool(String str) {
    if (str == 'true') {
      return true;
    } else {
      return false;
    }
  }

  /// object 轉為 string json
  static String object2string<T>(T t) {
    return fluroCnParamsEncode(jsonEncode(t));
  }

  /// string json 轉為 map
  static Map<String, dynamic> string2map(String str) {
    return json.decode(fluroCnParamsDecode(str));
  }
}
複製程式碼

2. Person.dart 等下用到的自定義型別

class Person{
  String name;
  int age;
  bool sex;

  Person({this.name, this.age,this.sex});

  Person.fromJson(Map<String, dynamic> json) {
    name = json['name'];
    age = json['age'];
    sex = json['sex'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['name'] = this.name;
    data['age'] = this.age;
    data['sex'] = this.sex;
    return data;
  }
}
複製程式碼

3. routes.dart

/// 配置路由地址 和 跳轉類和引數handler
static String demoParams = "/deme_params";

router.define(demoParams, handler: demoParamHandler);
複製程式碼

4. route_handlers.dart

/// 引數傳遞 int ,double,bool,自定義型別
var demoParamHandler = new Handler(
    handlerFunc: (BuildContext context, Map<String, List<Object>> params) {
  /// params["name"]?.first 相當於 params["name"][0] ,打個debug 你就知道為什麼了是個list
  String name = params["name"]?.first; 
  String age = params["age"]?.first;
  String sex = params["sex"]?.first;
  String score = params["score"]?.first;
  String personjson = params['personjson']?.first;
  /// 下面轉換為真實想要的型別
  return DemoParamsPage(
    name: name,
    age: FluroConvertUtils.string2int(age),
    score: FluroConvertUtils.string2double(score),
    sex: FluroConvertUtils.string2bool(sex),
    personJson: personjson,
  );
});	
複製程式碼

5. NavigatorUtil.dart

  /// 跳轉到 傳參demo 頁面
  static void goDemoParamsPage(BuildContext context, String name, int age,
      double score, bool sex, Person person) {
    /// 對中文進行編碼
    String mName = FluroConvertUtils.fluroCnParamsEncode(name);
    /// 對自定義型別 轉為 json string
    String personJson = FluroConvertUtils.object2string(person);
    Application.router.navigateTo(
        context,
        Routes.demoParams +
            "?name=$name&age=$age&score=$score&sex=$sex&personjson=$personJson");
  }
複製程式碼

6. home_page.dart 跳轉按鈕

String name = "來自第一個介面測試一下";
int age = 14;
double score = 6.4;
bool sex = true;
Person person = new Person(name: 'Zeking', age: 18, sex: true);

RaisedButton(
	child: Text('傳遞引數string ,int,double,bool ,自定義型別'),
	      onPressed: () {
	        NavigatorUtil.goDemoParamsPage(
	            context, name, age, score, sex, person);
	      },
	    ),
複製程式碼

7. demo_params_pag.dart

class DemoParamsPage extends StatefulWidget {
  final String name;
  final int age;
  final double score;
  final bool sex;
  final String personJson;

  DemoParamsPage({this.name, this.age, this.score, this.sex, this.personJson});

  @override
  _DemoParamsPageState createState() => _DemoParamsPageState();
}

class _DemoParamsPageState extends State<DemoParamsPage> {
  @override
  Widget build(BuildContext context) {
    /// 對 中文 進行解碼
    String mName = FluroConvertUtils.fluroCnParamsDecode(widget.name);
    /// 對自定義類 進行解析
    Person person =
        Person.fromJson(FluroConvertUtils.string2map(widget.personJson));
    print(person.name);
    print(person.age);
    print(person.sex);
    /// 下面的寫法也可以
    Map<String, dynamic> data = FluroConvertUtils.string2map(widget.personJson);
    print(data["name"]);
    print(data["age"]);
    print(data["sex"]);

    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('name:$mName'),
            Text('age:${widget.age}'),
            Text('score:${widget.score}'),
            Text('sex:${widget.sex}'),
            Text('Person:${person.toJson().toString()}'),
            RaisedButton(
              child: Text('返回'),
              onPressed: () {
                NavigatorUtil.goBack(context);
              },
            )
          ],
        ),
      ),
    );
  }
}
複製程式碼

5. 場景三:接收返回值 String,int,double,自定義型別

1. 效果圖

Flutter - 路由管理 - 02 -  Fluro

2. routes.dart

static String returnParams = "/return_params";

router.define(returnParams, handler: returnParamHandler);
複製程式碼

3. route_handlers.dart

/// 關閉頁面,返回引數
var returnParamHandler = new Handler(
    handlerFunc: (BuildContext context, Map<String, List<Object>> params) {
  return ReturnParamsPage();
});
複製程式碼

4. NavigatorUtil.dart

  /// 跳轉到 會返回引數的 頁面
  static Future goReturnParamsPage(BuildContext context) {
    return Application.router.navigateTo(context, Routes.returnParams);
  }
複製程式碼

5. home_page.dart

RaisedButton(
    child: Text('傳遞引數,接受返回值'),
     onPressed: () {
       NavigatorUtil.goReturnParamsPage(context).then((result) {
         debugPrint('${result.runtimeType}');
         String message  ;
         /// 如果是 自定義的 Person 類
         if (result.runtimeType == Person) {
           message = result.toJson().toString();
           debugPrint('${result.toJson().toString()}');
         } else {
           message = '$result';
           debugPrint('$result');
         }
         showResultDialog(context, message);
       });
     },
   )
   
  /// 顯示一個Dialgo
  void showResultDialog(BuildContext context,String message){
    showDialog(
      context: context,
      builder: (context) {
        return new AlertDialog(
          title: new Text(
            "Hey Hey!",
            style: new TextStyle(
              color: const Color(0xFF00D6F7),
              fontFamily: "Lazer84",
              fontSize: 22.0,
            ),
          ),
          content: new Text("$message"),
          actions: <Widget>[
            new Padding(
              padding: new EdgeInsets.only(bottom: 8.0, right: 8.0),
              child: new FlatButton(
                onPressed: () {
                  Navigator.of(context).pop(true);
                },
                child: new Text("OK"),
              ),
            ),
          ],
        );
      },
    );
  }
複製程式碼

6. return_params_page.dart

class ReturnParamsPage extends StatefulWidget {
  @override
  _ReturnParamsPageState createState() => _ReturnParamsPageState();
}

class _ReturnParamsPageState extends State<ReturnParamsPage> {
  @override
  Widget build(BuildContext context) {
    Person person = new Person(name: "returnName", age: 23, sex: false);
    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Center(
            child: RaisedButton(
              child: Text('返回,並且返回string'),
              onPressed: () {
                NavigatorUtil.goBackWithParams(context, "我是返回值哦");
              },
            ),
          ),
          RaisedButton(
            child: Text('返回,並且返回int'),
            onPressed: () {
              NavigatorUtil.goBackWithParams(context, 12);
            },
          ),
          RaisedButton(
            child: Text('返回,並且返回double'),
            onPressed: () {
              NavigatorUtil.goBackWithParams(context, 3.1415926);
            },
          ),
          RaisedButton(
            child: Text('返回,並且返回bool'),
            onPressed: () {
              NavigatorUtil.goBackWithParams(context, true);
            },
          ),
          RaisedButton(
            child: Text('返回,並且返回自定義型別'),
            onPressed: () {
              NavigatorUtil.goBackWithParams(context, person);
            },
          )
        ],
      ),
    );
  }
}
複製程式碼

6. 場景四:使用 框架 自帶 的 轉場動畫

1. 效果圖

Flutter - 路由管理 - 02 -  Fluro

2. routes.dart

static String transitionDemo = "/transitionDemo";

router.define(transitionDemo, handler: transitionDemoHandler);
複製程式碼

3. route_handlers.dart

/// 轉場動畫 頁面
var transitionDemoHandler = new Handler(
    handlerFunc: (BuildContext context, Map<String, List<Object>> params) {
  String title = params["title"]?.first;
  return TransitionDemoPage(title);
});
複製程式碼

4. NavigatorUtil.dart

  /// 跳轉到 轉場動畫 頁面 , 這邊只展示 inFromLeft ,剩下的自己去嘗試下,
  /// 框架自帶的有 native,nativeModal,inFromLeft,inFromRight,inFromBottom,fadeIn,custom
  static Future gotransitionDemoPage(BuildContext context, String title) {
    return Application.router.navigateTo(
        context, Routes.transitionDemo + "?title=$title",
        /// 指定了 轉場動畫 inFromLeft 
        transition: TransitionType.inFromLeft);
  }
複製程式碼

5. home_page.dart

RaisedButton(
  child: Text('框架 自帶 轉場動畫 演示'),
  onPressed: () {
    NavigatorUtil.gotransitionDemoPage(context,
		/// 這邊進行了 String 編碼
        FluroConvertUtils.fluroCnParamsEncode("框架 自帶 轉場動畫 演示 \n\n\n   "
            "這邊只展示 inFromLeft ,剩下的自己去嘗試下,\n\n\n   "
            "架自帶的有 native,nativeModal,inFromLeft,inFromRight,inFromBottom,fadeIn,custom"));
  },
),
複製程式碼

6. transition_demo_page.dart

場景五 ,場景六 ,用到一樣的 transition_demo_page 後面就不展示了

class TransitionDemoPage extends StatefulWidget {
  final String title;

  TransitionDemoPage(this.title);

  @override
  _TransitionDemoPageState createState() => _TransitionDemoPageState();
}

class _TransitionDemoPageState extends State<TransitionDemoPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Center(
              child: Text(
            /// string 解碼
            FluroConvertUtils.fluroCnParamsDecode(widget.title),
            textAlign: TextAlign.center,
          )),
          RaisedButton(
            child: Text('返回'),
            onPressed: () {
              NavigatorUtil.goBack(context);
            },
          )
        ],
      ),
    );
  }
}
複製程式碼

7. 場景五:自定義轉場動畫

1. 效果圖

Flutter - 路由管理 - 02 -  Fluro

2. routes.dart

static String transitionCustomDemo = "/transitionCustomDemo";

router.define(transitionCustomDemo, handler: transitionDemoHandler);
複製程式碼

3. route_handlers.dart

/// 轉場動畫 頁面
var transitionDemoHandler = new Handler(
    handlerFunc: (BuildContext context, Map<String, List<Object>> params) {
  String title = params["title"]?.first;
  return TransitionDemoPage(title);
});
複製程式碼

4. NavigatorUtil.dart

  /// 自定義 轉場動畫
  static Future gotransitionCustomDemoPage(BuildContext context, String title) {
    var transition = (BuildContext context, Animation<double> animation,
        Animation<double> secondaryAnimation, Widget child) {
      return new ScaleTransition(
        scale: animation,
        child: new RotationTransition(
          turns: animation,
          child: child,
        ),
      );
    };
    return Application.router.navigateTo(
        context, Routes.transitionCustomDemo + "?title=$title",
        transition: TransitionType.custom, /// 指定是自定義動畫
        transitionBuilder: transition, /// 自定義的動畫
        transitionDuration: const Duration(milliseconds: 600)); /// 時間
  }
複製程式碼

5. home_page.dart

 RaisedButton(
   child: Text('框架 自定義 轉場動畫 演示'),
   onPressed: () {
     NavigatorUtil.gotransitionCustomDemoPage(context,
         FluroConvertUtils.fluroCnParamsEncode('框架 自定義 轉場動畫 演示'));
   },
 ),
複製程式碼

8. 場景六:修改原始碼,新增使用 Flutter 的 cupertino 轉場動畫

1. 檢視原始碼,為什麼沒有 Flutter 的 cupertino

看下圖,發現它自帶的 轉場動畫 只有 這幾個,沒有我喜歡的Fluttercupertino轉場動畫,側滑關閉頁面,

Flutter - 路由管理 - 02 -  Fluro

繼續看原始碼 ,看下圖,最後也是呼叫了系統的MaterialPageRoutePageRouteBuilder

Flutter - 路由管理 - 02 -  Fluro

2. 修改原始碼

看下圖,自己新增 cupertino 型別

Flutter - 路由管理 - 02 -  Fluro
看下圖,新增CupertinoPageRoute

Flutter - 路由管理 - 02 -  Fluro

3. 效果圖

Flutter - 路由管理 - 02 -  Fluro

4. routes.dart

static String transitionCupertinoDemo = "/transitionCupertinoDemo";

router.define(transitionCupertinoDemo, handler: transitionDemoHandler);
複製程式碼

5. route_handlers.dart

/// 轉場動畫 頁面
var transitionDemoHandler = new Handler(
    handlerFunc: (BuildContext context, Map<String, List<Object>> params) {
  String title = params["title"]?.first;
  return TransitionDemoPage(title);
})
複製程式碼

6. NavigatorUtil.dart

  /// 使用 IOS 的 Cupertino 的轉場動畫,這個是修改了原始碼的 轉場動畫
  /// Fluro本身不帶,但是 Flutter自帶
  static Future gotransitionCupertinoDemoPage(
      BuildContext context, String title) {
    return Application.router.navigateTo(
        context, Routes.transitionCupertinoDemo + "?title=$title",
        transition: TransitionType.cupertino);
  }
複製程式碼

7. home_page.dart

 RaisedButton(
   child: Text('修改原始碼,新增使用 Flutter 的 cupertino 轉場動畫'),
   onPressed: () {
     NavigatorUtil.gotransitionCupertinoDemoPage(
         context,
         FluroConvertUtils.fluroCnParamsEncode(
             "修改原始碼,新增使用 Flutter 的 cupertino 轉場動畫"));
   },
複製程式碼

參考 github.com/theyakka/fl…

掃一掃,關注我的微信公眾號
都是一些個人學習筆記

Flutter - 路由管理 - 02 -  Fluro

點選下面閱讀原文,用電腦看,有目錄,更舒服哦

相關文章