走进Navigator 2.0
RoutePath

RouteInformationParser类
创建页面
RouteDelegate类



使用
调用流程
封装导航框架
hi_navigator.dart
typedef RouteChangeListener(RouteStatusInfo current, RouteStatusInfo pre);///创建页面pageWrap(Widget child) { return MaterialPage(key: ValueKey(child.hashCode), child: child);}///获取routeStatus在页面栈中的位置int getPageIndex(List<MaterialPage> pages, RouteStatus routeStatus) { for (int i = 0; i < pages.length; i++) { MaterialPage page = pages[i]; if (getStatus(page) == routeStatus) { return i; } } return -1;}///自定义路由封装,路由状态enum RouteStatus { login, registration, home, detail, unknown }///获取page对应的RouteStatusRouteStatus getStatus(MaterialPage page) { if (page.child is LoginPage) { return RouteStatus.login; } else if (page.child is RegistrationPage) { return RouteStatus.registration; } else if (page.child is BottomNavigator) { return RouteStatus.home; } else if (page.child is VideoDetailPage) { return RouteStatus.detail; } else { return RouteStatus.unknown; }}///路由信息class RouteStatusInfo { final RouteStatus routeStatus; final Widget page; RouteStatusInfo(this.routeStatus, this.page);}///监听路由页面跳转///感知当前页面是否压后台class HiNavigator extends _RouteJumpListener { static HiNavigator _instance; RouteJumpListener _routeJump; List<RouteChangeListener> _listeners = []; RouteStatusInfo _current; //首页底部tab RouteStatusInfo _bottomTab; HiNavigator._(); static HiNavigator getInstance() { if (_instance == null) { _instance = HiNavigator._(); } return _instance; } ///首页底部tab切换监听 void onBottomTabChange(int index, Widget page) { _bottomTab = RouteStatusInfo(RouteStatus.home, page); _notify(_bottomTab); } ///注册路由跳转逻辑 void registerRouteJump(RouteJumpListener routeJumpListener) { this._routeJump = routeJumpListener; } ///监听路由页面跳转 void addListener(RouteChangeListener listener) { if (!_listeners.contains(listener)) { _listeners.add(listener); } } ///移除监听 void removeListener(RouteChangeListener listener) { _listeners.remove(listener); } @override void onJumpTo(RouteStatus routeStatus, {Map args}) { _routeJump.onJumpTo(routeStatus, args: args); } ///通知路由页面变化 void notify(List<MaterialPage> currentPages, List<MaterialPage> prePages) { if (currentPages == prePages) return; var current = RouteStatusInfo(getStatus(currentPages.last), currentPages.last.child); _notify(current); } void _notify(RouteStatusInfo current) { if (current.page is BottomNavigator && _bottomTab != null) { //如果打开的是首页,则明确到首页具体的tab current = _bottomTab; } print('hi_navigator:current:${current.page}'); print('hi_navigator:pre:${_current?.page}'); _listeners.forEach((listener) { listener(current, _current); }); _current = current; }}///抽象类供HiNavigator实现abstract class _RouteJumpListener { void onJumpTo(RouteStatus routeStatus, {Map args});}typedef OnJumpTo = void Function(RouteStatus routeStatus, {Map args});///定义路由跳转逻辑要实现的功能class RouteJumpListener { final OnJumpTo onJumpTo; RouteJumpListener({this.onJumpTo});}
main.dart

class BiliRouteDelegate extends RouterDelegate<BiliRoutePath> with ChangeNotifier, PopNavigatorRouterDelegateMixin<BiliRoutePath> { final GlobalKey<NavigatorState> navigatorKey; //为Navigator设置一个key,必要的时候可以通过navigatorKey.currentState来获取到NavigatorState对象 BiliRouteDelegate() : navigatorKey = GlobalKey<NavigatorState>() { //实现路由跳转逻辑 HiNavigator.getInstance().registerRouteJump( RouteJumpListener(onJumpTo: (RouteStatus routeStatus, {Map args}) { _routeStatus = routeStatus; if (routeStatus == RouteStatus.detail) { this.videoModel = args['videoMo']; } notifyListeners(); })); /* //设置网络错误拦截器 HiNet.getInstance().setErrorInterceptor((error) { if (error is NeedLogin) { //清空失效的登录令牌 HiCache.getInstance().setString(LoginDao.BOARDING_PASS, null); //拉起登录 HiNavigator.getInstance().onJumpTo(RouteStatus.login); } }); */ } RouteStatus _routeStatus = RouteStatus.home; List<MaterialPage> pages = []; VideoModel videoModel; @override Widget build(BuildContext context) { var index = getPageIndex(pages, routeStatus); List<MaterialPage> tempPages = pages; if (index != -1) { //要打开的页面在栈中已存在,则将该页面和它上面的所有页面进行出栈 //tips 具体规则可以根据需要进行调整,这里要求栈中只允许有一个同样的页面的实例 tempPages = tempPages.sublist(0, index); } var page; if (routeStatus == RouteStatus.home) { //跳转首页时将栈中其它页面进行出栈,因为首页不可回退 pages.clear(); page = pageWrap(BottomNavigator()); } else if (routeStatus == RouteStatus.detail) { page = pageWrap(VideoDetailPage(videoModel)); } else if (routeStatus == RouteStatus.registration) { page = pageWrap(RegistrationPage()); } else if (routeStatus == RouteStatus.login) { page = pageWrap(LoginPage()); } //重新创建一个数组,否则pages因引用没有改变路由不会生效 tempPages = [...tempPages, page]; //通知路由发生变化 HiNavigator.getInstance().notify(tempPages, pages); pages = tempPages; return WillPopScope( //fix Android物理返回键,无法返回上一页问题@https://github.com/flutter/flutter/issues/66349 onWillPop: () async => !await navigatorKey.currentState.maybePop(), child: Navigator( key: navigatorKey, pages: pages, onPopPage: (route, result) { if (route.settings is MaterialPage) { //登录页未登录返回拦截 if ((route.settings as MaterialPage).child is LoginPage) { if (!hasLogin) { showWarnToast("请先登录"); return false; } } } //执行返回操作 if (!route.didPop(result)) { return false; } var tempPages = [...pages]; pages.removeLast(); //通知路由发生变化 HiNavigator.getInstance().noify(pages, tempPages); return true; }, ), ); } RouteStatus get routeStatus { if (_routeStatus != RouteStatus.registration && !hasLogin) { return _routeStatus = RouteStatus.login; } else if (videoModel != null) { return _routeStatus = RouteStatus.detail; } else { return _routeStatus; } } bool get hasLogin => LoginDao.getBoardingPass() != null; @override Future<void> setNewRoutePath(BiliRoutePath path) async {}}///定义路由数据,pathclass BiliRoutePath { final String location; BiliRoutePath.home() : location = "/"; BiliRoutePath.detail() : location = "/detail";}
home_page.dart
class HomePage extends StatefulWidget { const HomePage({Key key}) : super(key: key); @override _HomePageState createState() => _HomePageState();}class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin, TickerProviderStateMixin { var listener; TabController _controller; var tabs = ["推荐", "热门", "追播", "影视", "搞笑", "日常", "综合", "手机游戏", "短片·手书·配音"]; @override void initState() { super.initState(); _controller = TabController(length: tabs.length, vsync: this); HiNavigator.getInstance().addListener(this.listener = (current, pre) { print('home:current:${current.page}'); print('home:pre:${pre.page}'); if (widget == current.page || current.page is HomePage) { print('打开了首页:onResume'); } else if (widget == pre?.page || pre?.page is HomePage) { print('首页:onPause'); } }); } @override void dispose() { HiNavigator.getInstance().removeListener(this.listener); super.dispose(); } @override Widget build(BuildContext context) { super.build(context); return Scaffold( body: Column( children: [ Container( color: Colors.white, padding: EdgeInsets.only(top: 30), child: _tabBar(), ), Flexible( child: TabBarView( controller: _controller, children: tabs.map((tab) { return HomeTabPage(name: tab); }).toList())) ], ), ); } @override bool get wantKeepAlive => true; ///自定义顶部tab _tabBar() { return TabBar( controller: _controller, isScrollable: true, labelColor: Colors.black, indicator: UnderlineIndicator( strokeCap: StrokeCap.round, borderSide: BorderSide(color: primary, width: 3), insets: EdgeInsets.only(left: 15, right: 15)), tabs: tabs.map<Tab>((tab) { return Tab( child: Padding( padding: EdgeInsets.only(left: 5, right: 5), child: Text( tab, style: TextStyle(fontSize: 16), ), )); }).toList()); }}class HomeTabPage extends StatefulWidget { final String name; const HomeTabPage({Key key, this.name}) : super(key: key); @override _HomeTabPageState createState() => _HomeTabPageState();}class _HomeTabPageState extends State<HomeTabPage> { @override Widget build(BuildContext context) { return Container( child: Text(widget.name), ); }}
底部导航:PageView + BottomNavigationBar
///底部导航class BottomNavigator extends StatefulWidget { @override _BottomNavigatorState createState() => _BottomNavigatorState();}class _BottomNavigatorState extends State<BottomNavigator> { final _defaultColor = Colors.grey; final _activeColor = primary; int _currentIndex = 0; static int initialPage = 0; final PageController _controller = PageController(initialPage: initialPage); List<Widget> _pages; bool _hasBuild = false; @override Widget build(BuildContext context) { _pages = [HomePage(), RankingPage(), FavoritePage(), ProfilePage()]; if (!_hasBuild) { //页面第一次打开时通知打开的是那个tab HiNavigator.getInstance() .onBottomTabChange(initialPage, _pages[initialPage]); _hasBuild = true; } return Scaffold( body: PageView( controller: _controller, children: _pages, onPageChanged: (index) => _onJumpTo(index, pageChange: true), physics: NeverScrollableScrollPhysics(), ), bottomNavigationBar: BottomNavigationBar( currentIndex: _currentIndex, onTap: (index) => _onJumpTo(index), type: BottomNavigationBarType.fixed, selectedItemColor: _activeColor, items: [ _bottomItem('首页', Icons.home, 0), _bottomItem('排行', Icons.local_fire_department, 1), _bottomItem('收藏', Icons.favorite, 2), _bottomItem('我的', Icons.live_tv, 3), ], ), ); } _bottomItem(String title, IconData icon, int index) { return BottomNavigationBarItem( icon: Icon(icon, color: _defaultColor), activeIcon: Icon(icon, color: _activeColor), label: title); } void _onJumpTo(int index, {pageChange = false}) { if (!pageChange) { //让PageView展示对应tab _controller.jumpToPage(index); } else { HiNavigator.getInstance().onBottomTabChange(index, _pages[index]); } setState(() { //控制选中第一个tab _currentIndex = index; }); }}