每次推送使用不同的动画时如何正确执行 Navigator.popUntil

non*_*den 9 flutter

我正在尝试在 Flutter 中重建 iOS 应用程序,但面临导航问题。

这是我想要做的:

  1. 带有添加按钮的已添加交换对列表(A 屏幕)
  2. 添加按钮打开带有交换的选择器(B 屏幕),从底部到顶部过渡。
  3. 通过点击交换,它会推动新的 Picker with Pairs(C 屏幕),并从右向左过渡。
  4. 当用户点击配对时,它会立即关闭所有选择器并将选择结果发送到 A 屏幕。

我尝试过 double pop 和 popUntil 但结果总是一样,我同时看到 2 个后退转换(从左到右和从上到下)。

它在 iOS 本机应用程序中的外观:

它在 iOS 本机应用程序中的外观

它在 Flutter 应用程序中的外观:

它在 Flutter 应用程序中的外观

使用嵌套导航器解决

用导航器包裹屏幕 B 并使用此导航器推送屏幕 C,在屏幕 C 上使用根导航器弹出。结果如下: 最后结果

non*_*den 6

这是我如何解决它的示例:

import 'package:flutter/material.dart';

void main() {
  MaterialPageRoute.debugEnableFadingRoutes = true;
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String _result = "--";

  void _openSubscreen() {
    Navigator.of(context).push<String>(
      new MaterialPageRoute(
        settings: RouteSettings(name: '/subscreen'),
        builder: (context) => SubScreen(),
      ),
    ).then((result) => setState((){
      _result = result;
    }));
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Center(
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            new Text(
              'Result from navigator:',
            ),
            new Text(
              _result,
              textAlign: TextAlign.center,
              style: Theme.of(context).textTheme.headline,
            ),
            SizedBox(height: 32.0,),
            OutlineButton(
              onPressed: _openSubscreen,
              child: Text('Start flow'),
            ),
          ],
        ),
      ),
    );
  }
}

class SubScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: new Navigator(
        onGenerateRoute: (routeSettings) {
          final path = routeSettings.name;
          if (path == '/') {
            return new MaterialPageRoute(
              settings: routeSettings.copyWith(isInitialRoute: true),
              builder: (_) => SubScreenPage1(),
            );
          } else if (path == '/nexpage') {
            return new MaterialPageRoute(
              settings: routeSettings,
              builder: (_) => SubScreenPage2(),
            );
          }
        },
      ),
    );
  }
}

class SubScreenPage1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Center(
      child: OutlineButton(
        child: Text('Next sub page!'),
        onPressed: () {
          Navigator.of(context).pushNamed('/nexpage');
        },
      ),
    );
  }
}

class SubScreenPage2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Center(
      child: OutlineButton(
        child: Text('Deliver result!'),
        onPressed: () {
          final date = DateTime.now().toString();
          Navigator
              .of(context, rootNavigator: true)
              .pop('Delivered at $date');
        },
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)


Era*_*man 5

当您MaterialApp通过设置构建您的设置时home:routes:您可以实现“pop to root”,而无需硬编码要弹出的路径;

Navigator.popUntil(
  context,
  ModalRoute.withName(Navigator.defaultRouteName),
);
Run Code Online (Sandbox Code Playgroud)

因为Navigator.defaultRouteName将设置为您设置的任何内容home:

有点跑题,但是,如果您有“可变”主屏幕,这会特别好,就像使用 aFutureBuilder来决定主屏幕一样。例如,如果您在从磁盘加载初始状态之前一直显示启动画面。

home: isUserLoggedIn
    ? HomePage()
    : FutureBuilder(
        future: () async {
          print('Initializing');
          print('Waiting For NoReason');
          await Future.delayed(const Duration(seconds: 1));
          print('Initialization Complete');
        }(),
        builder: (_, snap) {
          if (snap.connectionState == ConnectionState.waiting) {
            return SplashPage();
          } else {
            return LogInPage();
          }
        },
      ),
Run Code Online (Sandbox Code Playgroud)