Flutter: routing, intercepting return events, custom independent routing

routing stack

There are two very important concepts in Flutter routing management:

  • Route: Routing is an abstraction of application pages, corresponding to Activity in Android and ViewController in iOS, managed by Navigator.
  • Navigator: Navigator is a component that manages and maintains a stack-based history, and jumps pages through push and pop.

simple example

class _YcHomeBodyState extends State<YcHomeBody> {
    
    
  
  Widget build(BuildContext context) {
    
    
    return Center(
      child: ElevatedButton(
        onPressed: () {
    
    
          // 使用PageRouteBuilder来加入淡入淡出的切换效果
          Navigator.of(context).push(PageRouteBuilder(
            transitionDuration: const Duration(milliseconds: 500),
            transitionsBuilder:
                (context, animation, secondaryAnimation, child) {
    
    
              return FadeTransition(
                opacity: animation,
                child: child,
              );
            },
            pageBuilder: (context, animation, secondaryAnimation) =>
                const SecondPage(),
          ));
        },
        child: const Text("跳转到B页面"),
      ),
    );
  }
}

class SecondPage extends StatelessWidget {
    
    
  const SecondPage({
    
    Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    
    
    return Scaffold(
      appBar: AppBar(
        title: const Text("B页面", style: TextStyle(color: Colors.white)),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
    
    
            Navigator.of(context).pop();
          },
          child: const Text("返回主页面"),
        ),
      ),
    );
  }
}

insert image description here

named route

Using named routes requires configuring route names in MaterialApp

configuration

MaterialApp(
      title: 'Flutter Demo',
      routes: <String, WidgetBuilder>{
    
    
        '/A': (context) => APage(),
        '/B': (context) => BPage(),
      },
      home: Scaffold(
        body: APage(),
      ),
    )

jump method

Navigator.of(context).pushNamed('/B');

// 页面替换,一般用于不希望再返回上一个页面,比如欢迎页和登录页
Navigator.of(context).pushReplacementNamed('/B');

// 用于判断路由是否可以出栈
Navigator.of(context).canPop()

// 路由出栈
Navigator.of(context).pop();

// 实现在跳转到新页面的同时,将之前的所有页面都清除掉,只保留当前页面
// 比如:应用程序进入首页,点击登录进入登录页面,然后进入注册页面或者忘记密码页面...,登录成功后进入其他页面,此时不希望返回到登录相关页面,此场景可以使用
Navigator.pushNamedAndRemoveUntil

Global routing switching animation

Use the route provided by the system to switch animations

fade animation

MaterialApp(
      routes: <String, WidgetBuilder>{
    
    
        '/A': (context) => const YcHomePage(),
        '/B': (context) => const SecondPage(),
      },
      // 设置页面过度主题
      theme: ThemeData(
        pageTransitionsTheme: const PageTransitionsTheme(
          builders: {
    
    
            TargetPlatform.android:FadeUpwardsPageTransitionsBuilder(),
            TargetPlatform.iOS:FadeUpwardsPageTransitionsBuilder()
          }
        )
      ),
      //指定显示哪一个页面
      home: const YcHomePage(),
    );
  }
}
  • FadeUpwardsPageTransitionsBuilder: Realize the effect of fading in from bottom to top when switching pages.
  • OpenUpwardsPageTransitionsBuilder: Used to build page transition animations from bottom to top. In this animation, new pages slide up from the bottom of the screen while old pages fade up.
  • ZoomPageTransitionsBuilder: Realize the zoom effect when the page is switched.
  • CupertinoPageTransitionsBuilder: IOS style page switching animation

Routing parameters

Constructor pass parameters

This method cannot be used for the jump method of the named route

Navigator.of(context).push(MaterialPageRoute(builder: (context){
    
    
  return ProductDetail(productInfo: productInfo,);
}));

class ProductDetail extends StatelessWidget {
    
    
  final ProductInfo productInfo;

  const ProductDetail({
    
    Key key, this.productInfo}) : super(key: key);
  
  
  Widget build(BuildContext context) {
    
    
    return Container();
  }
} 

Ways to set parameters via named routes

Main Page -> B Page

 // 发送参数
 Navigator.of(context).pushNamed('/B', arguments: '来自主页面');
 // 接收参数
 Text("B页面-${
      
      ModalRoute.of(context)?.settings.arguments}")

Page B -> Main Page

 // 发送参数
Navigator.of(context).pop('从B页面返回');
 // 接收参数
 ElevatedButton(
        onPressed: () async {
    
    
          String res = await Navigator.of(context).pushNamed('/B', arguments: '来自主页面') as String;
         setState((){
    
    
           title = res.toString();
         });
        },
         child:  Text(title),
),

insert image description here

Listen for application routing stack changes

For details, see: Monitor application routing stack changes

Customize RouteObserver, inherit RouteObserverand override the methods in it:

class MyRouteObserver<R extends Route<dynamic>> extends RouteObserver<R> {
    
    
  
  void didPush(Route route, Route? previousRoute) {
    
    
    super.didPush(route, previousRoute);
    print('didPush route: $route,previousRoute:$previousRoute');
  }

  
  void didPop(Route route, Route? previousRoute) {
    
    
    super.didPop(route, previousRoute);
    print('didPop route: $route,previousRoute:$previousRoute');
  }

  
  void didReplace({
    
    Route? newRoute, Route? oldRoute}) {
    
    
    super.didReplace(newRoute: newRoute, oldRoute: oldRoute);
    print('didReplace newRoute: $newRoute,oldRoute:$oldRoute');
  }

  
  void didRemove(Route route, Route? previousRoute) {
    
    
    super.didRemove(route, previousRoute);
    print('didRemove route: $route,previousRoute:$previousRoute');
  }

  
  void didStartUserGesture(Route route, Route? previousRoute) {
    
    
    super.didStartUserGesture(route, previousRoute);
    print('didStartUserGesture route: $route,previousRoute:$previousRoute');
  }

  
  void didStopUserGesture() {
    
    
    super.didStopUserGesture();
    print('didStopUserGesture');
  }
}

use

void main() {
    
    
  runApp(MyApp());
}

MyRouteObserver<PageRoute> myRouteObserver = MyRouteObserver<PageRoute>();

class MyApp extends StatelessWidget {
    
    
  
  Widget build(BuildContext context) {
    
    
    return MaterialApp(
      title: 'Flutter Demo',
      navigatorObservers: [myRouteObserver],
      initialRoute: '/A',
      home: APage(),
    );
  }
}

intercept return event

WillPopScopeis a widget in Flutter that can be used to control the behavior of the back button on Android and iOS platforms. Normally, when the user clicks the back button, the application closes the current page and returns to the previous page. However, sometimes we need to perform some custom operations when the user clicks the back button, such as popping up a confirmation dialog box or performing some data saving operations.

WillPopScopeIt is used to implement this custom back button behavior. It can listen to the event when the user clicks the back button and perform some action as needed. WillPopScopeIn , we can onWillPophandle the back button event through the callback function. If onWillPopit returns true, it means that it is allowed to close the current page and return to the previous page; if it returns false, it means that it is not allowed to close the current page.

Typically, it's placed in a property of the main page Scaffoldso bodythat when the user presses the back button, Scaffoldthe return action can be handled in .

Scaffold(
   //导航条
   appBar: AppBar(
     title: const Text("路由", style: TextStyle(color: Colors.white)),
   ),
   //页面主题内容
   body: WillPopScope(
     onWillPop: () async {
    
    
       bool confirmExit = await showDialog(
           context: context,
           builder: (content) {
    
    
             return AlertDialog(
               title: const Text('确定要推出吗?'),
               actions: [
                 ElevatedButton(
                     child: const Text('退出'),
                     onPressed: () => Navigator.of(context).pop(true)),
                 ElevatedButton(
                     child: const Text('取消'),
                     onPressed: () => Navigator.of(context).pop(false)),
               ],
             );
           });
       return confirmExit;
     },
     child: const YcHomeBody(),
   ));

insert image description here

Custom independent routing

NavigatorIt is a control that manages routing. Usually, it is directly used Navigator.of(context)to jump pages. The reason why it can be used directly is Navigator.of(context)because WidgetsAppthis control is used in MaterialApp. .MaterialAppNavigator

NavigatorThe usage is very simple, as follows:

Navigator(
  initialRoute: '/',
  onGenerateRoute: (RouteSettings settings) {
    
    
    WidgetBuilder builder;
    switch (settings.name) {
    
    
      case 'home':
        builder = (context) => PageA();
        break;
      case 'user':
        builder = (context) => PageB();
        break;
    }
    return MaterialPageRoute(builder: builder, settings: settings);
  },
)

initialRouteIt means to initialize the route, onGenerateRouteand means to generate a route according to RouteSettings.

common scene

So when do you need to use Navigator? Use Navigator where partial page jumps are required, as in the following scenarios:

Toutiao client report scene
Toutiao client has a "cross" under each news item, click on the relevant information to pop up, click on the report, and you will jump to the report page in the current small window. It is not a full-screen switch page, but just Switch on the currently popped-up page.

home page

class _YcHomeBodyState extends State<YcHomeBody> {
    
    
  
  Widget build(BuildContext context) {
    
    
    return Center(
      child: SizedBox(
        height: 350,
        width: 300,
        child: Navigator(
          initialRoute: '/',
          onGenerateRoute: (RouteSettings settins) {
    
    
            // 设置默认值
            WidgetBuilder builder = (content) => const Center();
            switch (settins.name) {
    
    
              case '/':
                builder = (context) => const SecondPage();
                break;
            }
            return MaterialPageRoute(builder: builder);
          },
        ),
      ),
    );
  }
}

SecondPagepage

class SecondPage extends StatelessWidget {
    
    
  const SecondPage({
    
    Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    
    
    return Center(
        child: SizedBox(
      height: 100,
      child: Card(
        child: Column(
          children: <Widget>[
            _buildItem(Icons.access_alarm, '举报', '标题夸张,内容质量差 等',
                showArrow: true, onPress: () {
    
    
              Navigator.of(context).push(MaterialPageRoute(builder: (context) {
    
    
                return const ThirdPage();
              }));
            }),
          ],
        ),
      ),
    ));
  }

  _buildItem(IconData iconData, String title, String content,
      {
    
    bool showArrow = false, required VoidCallback onPress}) {
    
    
    return Row(
      children: <Widget>[
        Icon(iconData),
        const SizedBox(
          width: 20,
        ),
        Expanded(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Text(
                title,
                style: const TextStyle(fontSize: 18),
              ),
              Text(
                content,
                style: TextStyle(
                    color: Colors.black.withOpacity(.5), fontSize: 14),
              )
            ],
          ),
        ),
        !showArrow
            ? Container()
            : IconButton(
                icon: const Icon(Icons.arrow_forward_ios),
                iconSize: 16,
                onPressed: onPress,
              ),
      ],
    );
  }
}

ThirdPage

class ThirdPage extends StatelessWidget {
    
    
  const ThirdPage({
    
    Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    
    
    return Container(
      height: 50,
      width: 250,
      color: Colors.grey.withOpacity(.5),
      child: Column(
        children: <Widget>[
          Row(
            children: <Widget>[
              IconButton(
                icon: const Icon(Icons.arrow_back_ios),
                onPressed: () {
    
    
                  Navigator.of(context).pop();
                },
              ),
              const Text("抱歉系统升级中,暂时无法举报")
            ],
          ),
        ],
      ),
    );
  }
}

Please add a picture description

Guess you like

Origin blog.csdn.net/weixin_41897680/article/details/131126659