Flutter 导航实现屏幕部分切换

17

我该如何将一个小部件推入另一个小部件的框架中?例如,我有一个包含2个容器的列,每个容器占据屏幕的一半。我想在底部容器中创建导航,就像iOS中的容器视图具有自己的UINavigationController一样。

据我所知,MaterialPageRoute只能将小部件推送到全屏幕,除了抽象类之外,没有其他Route类。也许我应该制作自己的ModalRoute/TransitionRoute子类?


你需要一些动画效果吗?或者为什么不使用条件语句来替换你的“容器”内容呢? - creativecreatorormaybenot
@creativecreatorormaybenot 我想使用英雄小部件,其动画由导航器触发。 - FashionYeti
3个回答

25
您可以使用Navigator小部件在应用程序中提供任意数量的单独导航器。每个导航器将维护自己的导航堆栈。例如,如果您想要将应用程序垂直拆分,使每个半部分都有自己的导航堆栈:
Column(
  children: <Widget>[
    Navigator(...),
    Navigator(...)
  ]
)

如果您这样做,您应该考虑如何处理Android返回按钮(现在您的应用程序技术上有3个导航器)。默认情况下,它只会监听您的根导航器,因此您需要在widget层次结构中提供一个WillPopScope小部件来捕获返回按钮事件并从适当的导航器弹出。


1
你如何精确地控制这两个导航器?你如何告诉一个导航器推送而另一个导航器弹出?如果您愿意在另一个问题中回答它,我可以发布一个问题。提前致谢。 - Archie G. Quiñones
3
从导航器的子小部件中,Navigator.of(context) 将返回正确的父级导航器。 - Kirollos Morkos
2
@KirollosMorkos 你能否提供一个例子。 - Rahul Dange

12

可能的一种解决方案是在屏幕上创建一个新的MaterialApp,并像常规应用程序一样(只是有不同的屏幕大小)从那里处理所有事情,例如:

可以考虑在该屏幕部分创建一个新的 MaterialApp,并且像处理普通应用程序一样处理所有内容(只是需要适应不同的屏幕尺寸),示例代码如下:

Column(
        children: <Widget>[
          Container(
            height: constraints.maxHeight * 0.5,
            width: constraints.maxWidth,
          ),
          Container(
              height: constraints.maxHeight * 0.5,
              width: constraints.maxWidth,
              child: MaterialApp(
                  debugShowCheckedModeBanner: false,
                  theme: ThemeData(
                    primaryColor: Color.fromRGBO(86, 86, 86, 1.00),
                  ),
                  initialRoute: '/W1',
                  routes: {
                    '/W1': (context) => WidgetOne(),
                    '/W2': (context) => WidgetTwo(),
                  })),
        ],
      ),

然后在小部件内部处理路由,就像这样:

class WidgetOne extends StatelessWidget {
@override
Widget build(BuildContext context) {
  return GestureDetector(
    onTap: () {
      Navigator.pushNamed(context, '/W2');
    },
    child: Container(color: Colors.green));
    }
  }
}

class WidgetTwo extends StatelessWidget {
@override
Widget build(BuildContext context) {
  return GestureDetector(
    onTap: () {
      Navigator.pushNamed(context, '/W1');
    },
    child: Container(color: Colors.pink));
    }
  }
}

结果: https://istack.dev59.com/qyJ5N.gif


非常感谢@Yodart。这正是我在寻找的。 - Rami Ibrahim

9

您可以使用 Navigator 作为您想要制作的特定部分的子级。 并且如果有前一个屏幕,则可以使用 WillPopScope 返回到前一个屏幕。 请确保使用 GlobalKey() 分隔每个导航器并为其提供唯一键。 我的代码:

var keyOne = GlobalKey<NavigatorState>();
var keyTwo = GlobalKey<NavigatorState>();
return Column(
  children: [
    Expanded(
      child: Container(
        child: WillPopScope(
          onWillPop: () async => !await keyOne.currentState.maybePop(),
          child: Navigator(
            key: keyOne,
            onGenerateRoute: (routeSettings) {
              return MaterialPageRoute(
                builder: (context) => ScreenOne(),
              );
            },
          ),
        ),
      ),
    ),
    Expanded(
      child: Container(
        child: WillPopScope(
          onWillPop: () async => !await keyTwo.currentState.maybePop(),
          child: Navigator(
            key: keyTwo,
            onGenerateRoute: (routeSettings) {
              return MaterialPageRoute(
                builder: (context) => ScreenTwo(),
              );
            },
          ),
        ),
      ),
    ),
  ],
);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接