路径

路径

大多数应用都会包含多个页面来显示不同类型的数据。比如,你有一个页面展示商品列表,用户可以通过点击其中的任意一个商品在另外一个页面查看该商品的详细信息。

在 Android 中,新的页面是 Activity。在 iOS 中,新的页面是 ViewController。在 Flutter 中,页面就是 widget !如果在 Flutter 中要切换页面,使用 Navigator widget 即可。

如何在页面之间进行切换?

在 React Native,有三种主要的导航 widget :StackNavigator, TabNavigator 和 DrawerNavigator。每个都提供了配置和定义页面的方法。

// React Native
const MyApp = TabNavigator(
  { Home: { screen: HomeScreen }, Notifications: { screen: tabNavScreen } },
  { tabBarOptions: { activeTintColor: '#e91e63' } }
);
const SimpleApp = StackNavigator({
  Home: { screen: MyApp },
  stackScreen: { screen: StackScreen }
});
export default (MyApp1 = DrawerNavigator({
  Home: {
    screen: SimpleApp
  },
  Screen2: {
    screen: drawerScreen
  }
}));

在 Flutter 中,有两种主要的 widget 实现页面之间的切换:

  • Route 是应用程序页面的一个抽象类。

  • Navigator 是管理页面路径的 widget。

Navigator 以堆栈的方式管理子 widget。它的堆栈里存储的是 Route 对象,并且提供方法管理整个堆栈,比如 Navigator.push和 Navigator.pop。路径列表需要在 MaterialApp 中指定。或者在页面切换的时候进行构建,比如 hero 动画。下面的例子在 MaterialApp widget 中指定了页面切换路径。

// Flutter
class NavigationApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
 widget build(BuildContext context) {
    return MaterialApp(
            ...
      routes: <String, WidgetBuilder>{
        '/a': (BuildContext context) => usualNavscreen(),
        '/b': (BuildContext context) => drawerNavscreen(),
      }
            ...
  );
  }
}

要切换到一个已命名的路径,Navigator 中的 of 方法被用于指定 BuildContext ( 该对象可以定位到 widget 树中的一个具体的 widget )。路径的名称传递到 pushNamed 函数来切换至指定的路径。

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

你可以使用 Navigator 中的 push 方法添加 route 到 navigator 的历史队列中,其中包含 context 并且可以切换到指定页面。在下面的例子中,MaterialPageRoute 是一个模式化路径,可以将整个页面通过平台自适应切换方式进行切换。它需要一个 WidgetBuilder 参数。

Navigator.push(context, MaterialPageRoute(builder: (BuildContext context)
 => UsualNavscreen()));

如何使用 tab 导航和 drawer 导航?

在 Material Design 应用程序中,Flutter 的导航形式主要有两种:tab 和 drawer。如果没有足够的 widget 可以容纳 tab,drawer 就是个不错的选择。

Tab navigation

Tab 导航

在 React Native 中,createBottomTabNavigator 和 TabNavigation 用来显示 tab 和 tab 导航。

// React Native
import { createBottomTabNavigator } from 'react-navigation';

const MyApp = TabNavigator(
  { Home: { screen: HomeScreen }, Notifications: { screen: tabNavScreen } },
  { tabBarOptions: { activeTintColor: '#e91e63' } }
);

Flutter 针对 drawer 和 tab 导航提供几种专用的 widget:

  • TabController—将 tab 与 TabBar 和 TabBarView 结合起来使用。

  • TabBar—水平显示一行 tab。

  • Tab—创建一个 material design 风格的 TabBar 中的 tab。

  • TabBarView—显示目前所选 tab 所对应的 widget。

// Flutter
TabController controller=TabController(length: 2, vsync: this);

TabBar(
  tabs: <Tab>[
    Tab(icon: Icon(Icons.person),),
    Tab(icon: Icon(Icons.email),),
  ],
  controller: controller,
),

要将 tab 选项与 TabBar 和 TabBarView 结合起来使用就需要 TabController。 TabController 的构造函数中的 length 参数定义了 tab 的总数。当状态变化时,需要使用 TickerProvider 来触发通知。TickerProvider 是 vsync。当你需要创建新的 TabController 时,将 vsync: this 作为构造函数的参数即可。

TickerProvider 接口可以用于生成 Ticker 对象。当有对象被触发通知后会用到 Tickers,不过它通常都是被 AnimationController 间接调用。AnimationControllers 需要 TickerProvider 来获得对应的 Ticker。如果你通过 State 创建了一个 AnimationController,那么你就可以使用 TickerProviderStateMixin 或者SingleTickerProviderStateMixin 来获得对应的 TickerProvider。

Scaffold 封装了一个新的 TabBar widget,其中包含两个 tab。TabBarView 作为 body 参数传递到 Scaffold 中。所有和 TabBar 中的 tab 相关的页面均是 TabBarView 的子 widget,并且都对应同一个 TabController。

// Flutter

class _NavigationHomePageState extends State<NavigationHomePage> with SingleTickerProviderStateMixin {
  TabController controller=TabController(length: 2, vsync: this);
  @override
 widget build(BuildContext context) {
    return Scaffold(
      bottomNavigationBar: Material (
        child: TabBar(
          tabs: <Tab> [
            Tab(icon: Icon(Icons.person),)
            Tab(icon: Icon(Icons.email),),
          ],
          controller: controller,
        ),
        color: Colors.blue,
      ),
      body: TabBarView(
        children: <Widget> [
          home.homeScreen(),
          tabScreen.tabScreen()
        ],
        controller: controller,
      )
    );
  }
}

Drawer 导航

在 React Native 中,导入所需的 react-navigation 包,然后使用 createDrawerNavigator 和 DrawerNavigation 实现。

// React Native
export default (MyApp1 = DrawerNavigator({
  Home: {
    screen: SimpleApp
  },
  Screen2: {
    screen: drawerScreen
  }
}));

在 Flutter 中,我们可以结合 Drawer 和 Scaffold 一起使用来实现 Material Design 风格的 drawer 布局。如果要在应用程序中添加 Drawer,可以将它封装在 Scaffold widget 中。Scaffold widget 提供了一种一致的界面风格,它遵循 Material Design 的设计原则。同时它还支持一些特殊的 Material Design 组件,比如 Drawers,AppBars,和 SnackBars。

Drawer 就是一个 Material Design 窗格,它可以从 Scaffold 边缘水平滑动显示应用程序的导航选项。你可以在里面添加 Button, Text。或者添加一个列表的元素作为 Drawer 的子 widget。在下面的例子中,ListTile 提供了点击导航。###

// Flutter
Drawer(
  child:ListTile(
    leading: Icon(Icons.change_history),
    title: Text('Screen2'),
    onTap: () {
      Navigator.of(context).pushNamed('/b');
    },
  ),
  elevation: 20.0,
),

Scaffold 还包含一个 AppBar。它会自动显示一个图标按钮来表明 Scaffold 中有一个Drawer。Scaffold 会自动处理边缘的滑动手势来显示 Drawer。

// Flutter
@override
Widget build(BuildContext context) {
  return Scaffold(
    drawer: Drawer(
      child: ListTile(
        leading: Icon(Icons.change_history),
        title: Text('Screen2'),
        onTap: () {
          Navigator.of(context).pushNamed('/b');
        },
      ),
      elevation: 20.0,
    ),
    appBar: AppBar(
      title: Text('Home'),
    ),
    body: Container(),
  );
}

Navigation on Android Android

Navigation on iOS iOS