Flutter實戰之路由功能篇

JulyYu發表於2020-02-11

跳轉功能

舉例常用頁面跳轉功能。

普通跳轉

  Navigator.of(context).push(
    MaterialPageRoute(
      builder: (_) => NextPage1(),
    ),
  );
複製程式碼

命名跳轉

Navigator.of(context).pushNamed("/router/nextPage");
複製程式碼

前提是需要在程式主入口配置路由表

MaterialApp(
      navigatorObservers: [UserNavigatorObserver()],
      initialRoute: "/",
      routes: {
        "/router": (context) => RouterDemo(),
        "/router/nextPage": (context) => NextPage2(),
      },
    );
複製程式碼

退出頁面

Navigator.of(context).pop(); //直接做退出操作
Navigator.of(context).maybePop(); //若為棧中最後一個頁面不做退出操作
複製程式碼

高階用法

popAndPushNamed

退出當前頁面並跳轉新頁面

Navigator.of(context).popAndPushNamed("/router/nextPage");
複製程式碼

等同於如下操作

Navigator.of(context).pop();
Navigator.of(context).push(
  MaterialPageRoute(
    builder: (_) => NextPage1(),
  ),
);
複製程式碼

PS: 但需要注意如果當前頁為棧底根頁面先執行pop再執行push會不會和popAndPushNamed執行結果不同呢?看原始碼就能會發現popAndPushNamed其實就是先執行pop再執行push的操作兩者執行結果一樣。

  @optionalTypeArgs
  Future<T> popAndPushNamed<T extends Object, TO extends Object>(
    String routeName, {
    TO result,
    Object arguments,
  }) {
    pop<TO>(result);
    return pushNamed<T>(routeName, arguments: arguments);
  }
複製程式碼

pushReplacementNamed

用法和popAndPushNamed類似,同樣是退出當前頁面並跳轉新頁面。但popAndPushNamed頁面出棧和入棧都有動畫,pushReplacementNamed則只有入棧動畫

Navigator.of(context).pushReplacementNamed("/router/next5");
複製程式碼

pushNamedAndRemoveUntil

將路由棧出棧到對應命名路由然後跳轉到新頁面,如下所示程式碼“ModalRoute.withName("/")”是將路由棧退到根路由並跳轉到“/router/nextPage”命名路由。 舉例當前路由棧為[1,2,3,4],執行pushNamedAndRemoveUntil開啟新頁面5,設定 ModalRoute.withName為2,最後路由棧為[1,2,5]。常用場景例如在個人設定頁面中多級子選單跳轉最後直接回到主頁操作。

Navigator.of(context).pushNamedAndRemoveUntil(
                "/router/nextPage",
                ModalRoute.withName("/"),
              );
複製程式碼

PS: 這裡要注意的是如果入棧非命名路由,不採用pushNamed入棧則ModalRoute.withName("/")會找不到要回退的位置,則跳轉的頁面不帶返回鍵,也就是說棧中就只剩下一個頁面。這點真的好奇是不是Flutter路由設計的問題,我暫時也沒有找到ModalRoute.withName對應的方法。

傳參功能

路由同時支援頁面之間的引數傳遞

入參傳遞

路由跳轉通過arguments欄位傳遞想要的入引數據,我們可以設定arguments為map物件傳遞更多入參。命名路由和直接路由傳遞arguments略有不同,命名路由直接通過arguments欄位傳遞,直接路由是通過settings欄位建立RouteSettings物件中的arguments傳遞。

  • 以命名路由跳轉時
Navigator.of(context).pushNamed(
  "/router/data2",
  arguments: {"data": "Hello"},
);
複製程式碼
  • 以頁面跳轉時
Navigator.of(context).push(
  MaterialPageRoute(
    builder: (context) => ChildDataDemo4(),
    settings: RouteSettings(
      arguments: {"data": "Hello"},
    ),
  ),
);
複製程式碼

接收頁面通過ModalRoute.of(context).settings獲取入參arguments得到資料。

class RouterChildDateDemo2 extends StatefulWidget {
  @override
  _RouterChildDateDemo2State createState() => _RouterChildDateDemo2State();
}

class _RouterChildDateDemo2State extends State<RouterChildDateDemo2> {
  @override
  Widget build(BuildContext context) {
    Map arguments = ModalRoute.of(context).settings.arguments;
    String data = arguments['data'];
    return Scaffold(
      appBar: AppBar(),
      body: Column(
        children: <Widget>[
          Text("data: $data"),
        ],
      ),
    );
  }
}
複製程式碼
  • 以直接路由構造方法
Navigator.of(context).push(
  MaterialPageRoute(
    builder: (context) => ChildDateDemo3("Hello"),
  ),
);
複製程式碼

資料接收頁面通過widget獲取入參。當然這種方式耦合性太高,對後期維護不利不推薦使用(雖然我自己專案中都是這麼寫,之後重構工作量巨大?)。

class ChildDateDemo3 extends StatefulWidget {
  final String data;

  ChildDateDemo3(this.data);

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

class _ChildDateDemo3State extends State<ChildDateDemo3> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Column(
        children: <Widget>[
          Text("data: ${widget.data}"),
        ],
      ),
    );
  }
}
複製程式碼

引數回傳

除了入參外,我們當然希望能夠在傳遞引數同時可以獲取到返回值。比如進入一個設定頁面在返回時獲取到上個頁面設定資料並顯示(雖然全域性狀態管理就能很好代替這方式)。

路由跳轉方法是有返回值Future,將跳轉方法設定為async通過await獲取結果。

var result = await Navigator.of(context).push(
  MaterialPageRoute(
    builder: (context) => ChildDataDemo5(),
  ),
);
setState(() {
  this.result = result.toString();
});
複製程式碼

當要返回上級頁面回傳結果時在pop方法中傳遞需要返回泛型引數(使用字典是比較好的資料結構)。

Navigator.of(context).pop({"data": "Bye"});
複製程式碼

動畫過渡

替換MaterialPageRoute使用PageRouteBuilder做路由跳轉。通過transitionsBuilder建立AnimatedWidget物件實現動畫效果。如下設定一個SlideTransition滑動過渡動畫通過起始和結束的偏移量達到側邊滑出效果

Navigator.of(context).push(
  PageRouteBuilder(
    pageBuilder: (BuildContext context,
        Animation<double> animation1,
        Animation<double> animation2) {
      return AniDemo2();
    },
    transitionsBuilder: (BuildContext context,
        Animation<double> animation1,
        Animation<double> animation2,
        Widget child) {
      return SlideTransition(
        position: Tween<Offset>(
          begin: Offset(-1.0, 0.0),
          end: Offset(0.0, 0.0),
        ).animate(
          animation1,
        ),
        child: child,
      );
    },
  ),
);
複製程式碼

Demo程式碼地址

可參考demo瞭解路由程式碼和路由使用。

參考

相關文章