[Flutter]flutter基础之组件基础(六)

一、概述

上篇文章介绍 MaterialAppScaffold ,但是没有内容比较多,没有介绍完毕。本篇文章继续上文继续说明。

二、 Scaffold Widget 补充

bottomNavigationBarScaffold 的属性,用来设置应用程序的底部应用或导航栏,其是一个 Widget ,通常使用 BottomAppBarBottomNavigationBar 。主要用来显示消息以及提供特定功能的导航。

BottomAppBar 是一个顶部可以有凹口的 Widget ,是一个 StatefulWidget 。通常与 FloatingActionButton 一起使用。其构造方法如下:

const BottomAppBar({
  Key key,
  //Color类型可选命名参数,底部程序栏的背景色
  this.color,
  //double类型可选命名参数,相对于其父应用程序栏放置底部应用程序栏的z坐标
  this.elevation,
  //NotchedShape类型可选命名参数,为浮动操作按钮制作的凹槽
  this.shape,
  //Clip类型可选命名参数,设置内容裁剪方式
  this.clipBehavior = Clip.none,
  //double类型可选命名参数,浮动动作按钮和底部应用栏的凹口之间的边距
  this.notchMargin = 4.0,
  //Widget类型可选命名参数,要显示的Widget
  this.child,
})

使用如下:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyFirstPage(),
    );;
  }
}

class MyFirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Page 1"),
      ),
      body: Container(
        color: Colors.yellow,
        child: Center(child: Text("主体内容"),),
      ),
      endDrawer: Drawer(),
      bottomNavigationBar: BottomAppBar(
        color: Colors.deepPurpleAccent,
        child: Text("底部BottomAppBar"),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: (){
          print("点击");
        },
        child: Icon(Icons.add),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
    );
  }
}

如果不提供 BottomAppBarchild 设置,不会抛出异常,但是不会显示 BottomAppBar

本例的效果如下:

2020312245.jpg

如果想要设置 BottomAppBar 的高度,可以通过嵌套使用带有高度的 Widget ,如下使用 Container

class MyFirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Page 1"),
      ),
      body: Container(
        color: Colors.yellow,
        child: Center(child: Text("主体内容"),),
      ),
      endDrawer: Drawer(),
      bottomNavigationBar: BottomAppBar(
        color: Colors.deepPurpleAccent,
        child: Container(
          child: Text("底部BottomAppBar"),
          height: 50.0,
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: (){
          print("点击");
        },
        child: Icon(Icons.add),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
    );
  }
}
2020312513.jpg

使用有凹口的 BottomAppBar 需要 shapeFloatingActionButtonLocation.centerDockedFloatingActionButtonLocation.endDocked 配合使用。如下:

class MyFirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Page 1"),
      ),
      body: Container(
        color: Colors.yellow,
        child: Center(child: Text("主体内容"),),
      ),
      endDrawer: Drawer(),
      bottomNavigationBar: BottomAppBar(
        color: Colors.deepPurpleAccent,
        shape: const CircularNotchedRectangle(),
        child: Container(
          height: 50.0,
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: (){
          print("点击");
        },
        child: Icon(Icons.add),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
    );
  }
}

效果如下图:

2020312725.jpg

BottomAppBar 中也可以显示多个 Widget ,需要使用 Row 横向布局 Widget 容器,后面会详细介绍 Row 。使用如下:

class MyFirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Page 1"),
      ),
      body: Container(
        color: Colors.yellow,
        child: Center(child: Text("主体内容"),),
      ),
      endDrawer: Drawer(),
      bottomNavigationBar: BottomAppBar(
        color: Colors.deepPurpleAccent,
        shape: const CircularNotchedRectangle(),
        child: Container(
          child: Row(
            children: <Widget>[
              IconButton(icon: Icon(Icons.print), onPressed: (){}),
              IconButton(icon: Icon(Icons.add), onPressed: (){}),
              IconButton(icon: Icon(Icons.add_a_photo), onPressed: (){}),
            ],
          ),
          height: 50.0,
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: (){
          print("点击");
        },
        child: Icon(Icons.add),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
    );
  }
}

效果如下图:

2020312739.jpg

BottomNavigationBar 主要用于应用的底部导航,继承自 StatefulWidget ,为有状态的 Widget ,构造函数如下:

BottomNavigationBar({
  Key key,
  //List<BottomNavigationBarItem>类型必传参数,底部导航栏中的选项
  @required this.items,
  //ValueChanged<int>类型可选命名参数,点击某个选项时的回调函数
  this.onTap,
  //int类型可选命名参数,当前被选择的选项索引
  this.currentIndex = 0,
  //double类型可选命名参数,此底部导航栏的z坐标。
  this.elevation = 8.0,
  //BottomNavigationBarType类型可选命名参数,定义底部导航栏的布局和行为
  BottomNavigationBarType type,
  //Color类型可选命名参数,被选择的选项的颜色,get属性
  Color fixedColor,
  //Color类型可选命名参数,底部导航栏背景色
  this.backgroundColor,
  //double类型可选命名参数,底部导航中的图标的大小
  this.iconSize = 24.0,
  //Color类型可选命名参数,所选底部导航图标和底部导航图标标签的颜色
  Color selectedItemColor,
  //Color类型可选命名参数,未选择的底部导航图标和底部导航图标标签的颜色
  this.unselectedItemColor,
  //IconThemeData类型可选命名参数,当前选定的底部导航图标中图标的大小、不透明度和颜色
  this.selectedIconTheme = const IconThemeData(),
  //IconThemeData类型可选命名参数,当前未选中的底部导航图标中图标的大小、不透明度和颜色
  this.unselectedIconTheme = const IconThemeData(),
  //double类型可选命名参数,选择时底部导航项标签的字体大小
  this.selectedFontSize = 14.0,
  //double类型可选命名参数,未选择时底部导航项标签的字体大小
  this.unselectedFontSize = 12.0,
  //TextStyle类型可选命名参数,选择时底部导航项标签的文本样式。
  this.selectedLabelStyle,
  //TextStyle类型可选命名参数,未选择时底部导航项标签的文本样式。
  this.unselectedLabelStyle,
  //bool类型可选命名参数,是否为选择的底部导航图标显示标签文本
  this.showSelectedLabels = true,
  //bool类型可选命名参数,是否为未选定的底部导航项显示标签文本
  bool showUnselectedLabels,
})

BottomNavigationBarItem 为带有图标和标题的交互式按钮,通常与 BottomNavigationBar 一起使用,构造方法如下:

const BottomNavigationBarItem({
  //Widget类型必传参数,底部导航选项的图标
  @required this.icon,
  //Widget类型可选命名参数,底部导航选项的标题
  this.title,
  //Widget类型可选命名参数,选择底部导航选项的替代图标。当选项被选择时将使用此设置的图标,如果不为null
  Widget activeIcon,
  //Color类型可选命名参数,底部导航栏的背景径向动画的颜色。只有当设置BottomNavigationBarType.shifting
  //时才生效,点击后底部导航背景色将变化为此色
  this.backgroundColor,
})

使用方法如下:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyRootNavigationPage(),
    );;
  }
}

class MyRootNavigationPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return _MyRootNavigationPage();
  }
}

class _MyRootNavigationPage extends State<MyRootNavigationPage> {

  final List<String> _pageTitles = <String>[
    "page 1",
    "page 2",
    "page 3"
  ];
  String _pageTitle;
  int _currentSelected = 0;
  final List<Widget> _pageWidget = <Widget>[
    _FirstPage(),
    _SecondPage(),
    _ThirdPage(),
  ];

  _itemSelected(int valueIndex) {
    setState(() {
      _currentSelected = valueIndex;
      _pageTitle = _pageTitles.elementAt(valueIndex);
    });
  }

  @override
  void initState() {
    super.initState();
    _pageTitle = _pageTitles.first;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("$_pageTitle"),
      ),
      body: Container(
        child: _pageWidget.elementAt(_currentSelected),
      ),
      endDrawer: Drawer(),
      bottomNavigationBar: BottomNavigationBar(
        items: <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.print),
            title: Text("Page1"),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.party_mode),
            title: Text("Page2"),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.add_a_photo),
            title: Text("Page3"),
          ),
        ],
        currentIndex: _currentSelected,
        onTap: _itemSelected,
        backgroundColor: Colors.yellowAccent,
        selectedItemColor: Colors.red,
        unselectedItemColor: Colors.black45,
      ),
    );
  }
}

class _FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(child: Text("Page 1"));
  }
}

class _SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(child: Text("Page 2"));
  }
}

class _ThirdPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(child: Text("Page 3"));
  }
}

对于 BottomNavigationBarItem 内的显示图标,可以使用 Image 加载自定义的图片。上述代码效果如下:

20203121058.jpg

BottomNavigationBartypeBottomNavigationBarType 类型,是一个枚举类型,如下:

enum BottomNavigationBarType {
  //底部导航条的底部导航条有固定的宽度
  fixed,

  //底部导航栏底部导航栏的位置和大小动画和标签在被点击时淡入
  shifting,
}

ScaffoldpersistentFooterButtonsList<Widget> 类型,是一组显示在 Scaffold 底部的 Widget ,通常使用 FlatButton 。这组 Widget 会呈现在 bottomNavigationBar 的上方,body 下方。他们是持续可见的,即使 body 进行滚动依然如此。使用方式如下:

persistentFooterButtons: <Widget>[
        FlatButton(onPressed: (){}, child: Text("按钮1")),
        FlatButton(onPressed: (){}, child: Text("按钮1")),
        FlatButton(onPressed: (){}, child: Text("按钮1"))
      ],

效果如下图:

20203121115.jpg

bottomSheet 对应的是一个 Widget ,是一个始终可见的 Widget 。可以用来定义底部的菜单或对话框。也可以使用 Flutter 提供好的

使用任意 Widget 的方法如下:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyFirstPage(),
    );;
  }
}

class MyFirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Page 1"),
      ),
      body: Container(
        color: Colors.yellow,
        child: Center(child: Text("主体内容"),),
      ),
      bottomSheet: Container(    //bottomSheet
        color: Colors.red,
        height: 80,
        child: Center(child: Text("BottomSheet")),
      ),
      endDrawer: Drawer(),
    );
  }
}

效果如下图:

2020313235.jpg

在底部展示消息还可以使用 SnackBar Widget ,其是一个 StatefulWidget ,是一个轻量级的带有可选操作的在屏幕底部暂时出现的 Widget。其构造方法如下:

const SnackBar({
  Key key,
  //Widget类型必传参数,要显示的Widget
  @required this.content,
  //Color类型可选命名参数,用于指定背景色
  this.backgroundColor,
  //double类型可选命名参数,SnackBar的z坐标,这可以控制SnackBar下方阴影的大小
  this.elevation,
  //ShapeBorder类型可选命名参数,SnackBar的形状
  this.shape,
  //SnackBarBehavior类型可选命名参数,用于设置SnackBar的行为和位置
  this.behavior,
  //SnackBarAction类型可选命名参数,要执行的行为
  this.action,
  //Duration类型可选命名参数,SnackBar的持续显示时间
  this.duration = _snackBarDisplayDuration,
  //Animation<double>类型可选命名参数,动画
  this.animation,
  //VoidCallback类型可选命名参数,第一次在Scaffold中出现时的回调函数
  this.onVisible,
})

使用如下:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyFirstPage(),
    );;
  }
}

class MyFirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Page 1"),
      ),
      body: Builder(
        builder: (BuildContext context){
          return Container(
            color: Colors.yellow,
            child: Center(
              child: RaisedButton(
                child: Text("SnackBar"),
                onPressed: (){
                  ScaffoldState state = Scaffold.of(context);
                  SnackBar snBar = SnackBar(
                    content: Text("这是一个提示信息"),
                    backgroundColor: Colors.deepPurpleAccent,
                    action: SnackBarAction(
                      label: "点击查看详情",
                      onPressed: (){
                        print("详情内容");
                      },
                    ),
                    onVisible: ()=> print("第一次出现执行,仅执行一次"),
                  );
                  state.showSnackBar(snBar);
                },
              ),
            ),
          );
        },
      ),
      endDrawer: Drawer(),
    );
  }
}

效果如下:

2020314732.gif

三、MaterialApp Widget 补充

MaterialApp 中的 themedarkTheme 均是 ThemeData 类型,用于设置应用的主题颜色和板式值。可以配置 ThemeMaterialApp Widget ,获取当前的主题,可以使用 Theme.of 。区别在于 darkTheme 意思是提供暗黑模式的主题,在设置 ThemeDataBrightness 时应设置为 dark 。如果同时提供 themedarkTheme ,则可以设置 themeMode 进行主题选择,这就是同时提供两种主题模式的用途,可以通过不同的设置提供不同的主题样式。主题主要用来定义应用程序通用的样式和颜色基调,可以再对不同的 Widget 做具体细节调整。其构工厂造函数如下:

factory ThemeData({
  //Brightness类型可选命名参数,用于设置主题的模式,dark或者light
  Brightness brightness,
  //MaterialColor类型可选命名参数,用于定义一种单一的颜色,此颜色带有始终色调的颜色样本
  MaterialColor primarySwatch,
  //Color类型可选命名参数,用于设置工具栏、标签栏等的背景色
  Color primaryColor,
  //Brightness类型可选命名参数,在主题模式不变的情况下设置基色(工具栏等)的文本和图标反色
  Brightness primaryColorBrightness,
  //Color类型可选命名参数,原色的较轻版本
  Color primaryColorLight,
  //Color类型可选命名参数,原色的较暗版本
  Color primaryColorDark,
  //Color类型可选命名参数,小部件的前景色(旋钮、文本、过卷边缘效果等)
  Color accentColor,
  //Brightness类型可选命名参数,用于确定放置在强调色顶部的文本和图标的颜色(例如,浮动操作按钮上的图标)
  Brightness accentColorBrightness,
  //Color类型可选命名参数,画布颜色
  Color canvasColor,
  //Color类型可选命名参数,Scaffold的页面背景色
  Color scaffoldBackgroundColor,
  //Color类型可选命名参数,底部应用栏的默认颜色
  Color bottomAppBarColor,
  //Color类型可选命名参数,Card的颜色
  Color cardColor,
  //Color类型可选命名参数,分隔线和弹出窗口的颜色也用于列表间、数据表中的行间等等
  Color dividerColor,
  //Color类型可选命名参数,使用的焦点颜色表示组件具有输入焦点
  Color focusColor,
  //Color类型可选命名参数,用于指示指针何时悬停在组件上的悬停颜色
  Color hoverColor,
  //Color类型可选命名参数,高亮颜色
  Color highlightColor,
  //Color类型可选命名参数,InkWell颜色
  Color splashColor,
  //InteractiveInkFeatureFactory类型可选命名参数,定义墨水池和墨水响应产生的墨水飞溅的外观
  InteractiveInkFeatureFactory splashFactory,
  //Color类型可选命名参数,用于突出显示选定行的颜色
  Color selectedRowColor,
  //Color类型可选命名参数,处于非活动(但已启用)状态的小部件所用的颜色
  Color unselectedWidgetColor,
  //Color类型可选命名参数,不工作的小部件所用的颜色,与它们的状态无关
  Color disabledColor,
  //Color类型可选命名参数,“凸起”按钮中使用的材料的默认填充颜色
  Color buttonColor,
  //ButtonThemeData类型可选命名参数,定义按钮小部件的默认配置,如上升按钮和平板按钮
  ButtonThemeData buttonTheme,
  //ToggleButtonsThemeData类型可选命名参数,定义ToggleButtons小部件的默认配置
  ToggleButtonsThemeData toggleButtonsTheme,
  //Color类型可选命名参数,当有选定行时,分页数据表的标题颜色
  Color secondaryHeaderColor,
  //Color类型可选命名参数,文本字段中文本选择的颜色,如文本字段
  Color textSelectionColor,
  //Color类型可选命名参数,TextField(如文本字段)等中光标的颜色
  Color cursorColor,
  //Color类型可选命名参数,用于调整当前所选文本部分的手柄颜色
  Color textSelectionHandleColor,
  //Color类型可选命名参数,与原色形成对比的颜色,例如用作进度条的剩余部分
  Color backgroundColor,
  //Color类型可选命名参数,对话框元素的背景颜色
  Color dialogBackgroundColor,
  //Color类型可选命名参数,标签栏中所选标签指示器的颜色
  Color indicatorColor,
  //Color类型可选命名参数,用于提示文本或占位符文本的颜色,例如在文本字段中
  Color hintColor,
  //Color类型可选命名参数,用于输入验证错误的颜色,例如在文本字段中
  Color errorColor,
  //Color类型可选命名参数,用于突出显示可切换小部件(如开关、收音机和复选框)活动状态的颜色
  Color toggleableActiveColor,
  //String类型可选命名参数,用于设置字体名称
  String fontFamily,
  //TextTheme类型可选命名参数,文字颜色与卡片和画布颜色
  TextTheme textTheme,
  //TextTheme类型可选命名参数,与原色形成对比的文本主题
  TextTheme primaryTextTheme,
  //TextTheme类型可选命名参数,与强调色形成对比的文本主题
  TextTheme accentTextTheme,
  //InputDecorationTheme类型可选命名参数,输入编辑器、文本字段和文本表单字段的默认输入配置值基于此主题
  InputDecorationTheme inputDecorationTheme,
  //IconThemeData类型可选命名参数,与卡片和画布颜色形成对比的图标主题
  IconThemeData iconTheme,
  //IconThemeData类型可选命名参数,与原色形成对比的图标主题
  IconThemeData primaryIconTheme,
  //IconThemeData类型可选命名参数,与强调色形成对比的图标主题
  IconThemeData accentIconTheme,
  //SliderThemeData类型可选命名参数,用于渲染滑块的颜色和形状
  SliderThemeData sliderTheme,
  //TabBarTheme类型可选命名参数,用于自定义标签栏指示器的大小、形状和颜色的主题
  TabBarTheme tabBarTheme,
  //TooltipThemeData类型可选命名参数,用于自定义工具提示视觉属性的主题
  TooltipThemeData tooltipTheme,
  //CardTheme类型可选命名参数,用于渲染卡片的颜色和样式
  CardTheme cardTheme,
  //ChipThemeData类型可选命名参数,用于渲染芯片的颜色和样式
  ChipThemeData chipTheme,
  //TargetPlatform类型可选命名参数,材料部件应适应目标的平台
  TargetPlatform platform,
  //MaterialTapTargetSize类型可选命名参数,配置某些材质小部件的命中测试大小
  MaterialTapTargetSize materialTapTargetSize,
  //bool类型可选命名参数,在材质表面应用半透明叠加颜色,以指示深色主题的高度
  bool applyElevationOverlayColor,
  //PageTransitionsTheme类型可选命名参数,每个目标平台的默认材质页面输出转换
  PageTransitionsTheme pageTransitionsTheme,
  //AppBarTheme类型可选命名参数,用于自定义应用栏的颜色、高度、亮度、图标主题和文本主题的主题
  AppBarTheme appBarTheme,
  //BottomAppBarTheme类型可选命名参数,用于自定义底部工具栏的形状、高度和颜色的主题
  BottomAppBarTheme bottomAppBarTheme,
  //ColorScheme类型可选命名参数,一组十三种颜色,可用于配置大多数组件的颜色属性
  ColorScheme colorScheme,
  //DialogTheme类型可选命名参数,用于自定义对话框形状的主题
  DialogTheme dialogTheme,
  //FloatingActionButtonThemeData类型可选命名参数,用于自定义浮动动作按钮的形状、高度和颜色的主题
  FloatingActionButtonThemeData floatingActionButtonTheme,
  //Typography类型可选命名参数,用于配置文本主题、主文本主题和重音文本主题的颜色和几何文本主题值
  Typography typography,
  //CupertinoThemeData类型可选命名参数,要从“材料”主题“数据”自适应中覆盖的CupertinoThemeData的组件
  CupertinoThemeData cupertinoOverrideTheme,
  //SnackBarThemeData类型可选命名参数,用于自定义SnackBar的颜色、形状、高度和行为的主题
  SnackBarThemeData snackBarTheme,
  //BottomSheetThemeData类型可选命名参数,用于自定义底部工作表的颜色、高度和形状的主题
  BottomSheetThemeData bottomSheetTheme,
  //PopupMenuThemeData类型可选命名参数,用于自定义弹出菜单的颜色、形状、高度和文本样式的主题
  PopupMenuThemeData popupMenuTheme,
  //MaterialBannerThemeData类型可选命名参数,用于自定义材质横幅的颜色和文本样式的主题
  MaterialBannerThemeData bannerTheme,
  //DividerThemeData类型可选命名参数,自定义分割线、垂直分割线等的颜色、厚度和缩进的主题
  DividerThemeData dividerTheme,
  //ButtonBarThemeData类型可选命名参数,自定义按钮栏小部件外观和布局的主题
  ButtonBarThemeData buttonBarTheme,
})

关于 ThemeData 的不同属性只是翻译自官方文档,部分没有做验证看效果,各位要自己试验看效果。

locale 用于设置应用程序的本地语言初始化环境值。如果为 null ,则使用系统的区域设置值。如果 Localizations.locale 的值与 supportedLocales 之一匹配,则它将等于该语言环境。 否则它将是第一个 supportedLocale

关于国际化的使用方式查看官方网址:https://flutter.dev/docs/development/accessibility-and-localization/internationalization 。后续文章也会详细介绍。

上述说的都是单独的界面,如果涉及到页面的切换,比如查看列表的详细信息,进入下一级等,需要使用到 Navigator Widget 。

Navigator 是使用堆栈规则管理一组 Widget ,这些 Widget (界面)称为 Route 对象 。其继承自 StatefulWidget ,是一个有状态的 Widget 。其构造方法如下:

const Navigator({
  Key key,
  //String类型可选命名参数,要显示的第一个路由(页面)的名称
  this.initialRoute,
  //RouteFactory类型必传参数,调用以生成给定路由设置的路由
  @required this.onGenerateRoute,
  //RouteFactory类型必传参数,当onGenerateRoute无法生成路由时调用
  this.onUnknownRoute,
  //List<NavigatorObserver>类型必传参数,导航器的观察者列表
  this.observers = const <NavigatorObserver>[],
})

在执行路由线路切换需要使用 Navigatorpushpop 方法,如下:

//将制定路由添加到到导航的路由栈中
@optionalTypeArgs
static Future<T> push<T extends Object>(BuildContext context, Route<T> route) {
  return Navigator.of(context).push(route);
}

//用于弹出最顶端的路由
@optionalTypeArgs
static bool pop<T extends Object>(BuildContext context, [ T result ]) {
  return Navigator.of(context).pop<T>(result);
}

Navigator.push() 接收两个参数,一个是上下文信息,另一个是 Route ,可以使用 MaterialPageRote的实例。其构造函数如下:

MaterialPageRoute({
  //WidgetBuilder类型必传参数,构建路线的主要内容
  @required this.builder,
  //RouteSettings类型可选命名参数,路由的设置
  RouteSettings settings,
  //bool类型可选命名参数,路由处于非活动状态时是否应保留在内存中
  this.maintainState = true,
  //bool类型可选命名参数,此页面路由是否为全屏对话框。在iOS上,
  //这些页面从底部到顶部(而不是水平)进行动画处理。
  bool fullscreenDialog = false,
})

使用方式如下:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );;
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("HomePage"),
      ),
      body: Builder(
        builder: (BuildContext context){
          return Container(
            color: Colors.yellow,
            child: Center(
              child: RaisedButton(
                child: Text("下一页"),
                onPressed: (){
                 Navigator.push(context, MaterialPageRoute(
                   builder: (context) => FirstPage(),
                   fullscreenDialog: false,  //如果为true,则动画为从下至上推出
                 ));
                },
              ),
            ),
          );
        },
      ),
      endDrawer: Drawer(),
    );
  }
}

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("FirstPage"),
      ),
      body: Center(
        child: RaisedButton(
          child: Text("上一页"),
          onPressed: (){
            Navigator.pop(context);
          },
        ),
      ),
    );
  }
}

效果如下:

2020315123.gif

也可以通过设置 Material.routes 来设置导航的顶级路由路线,通过 Navigator.pushNamed 方法进行导航界面切换,pushNamed 方法原型如下:

@optionalTypeArgs
static Future<T> pushNamed<T extends Object>(
  //BuildContext类型必传参数,上线文
  BuildContext context,
  //String类型必传参数,路由路径名称
  String routeName, {
  //Object类型可选命名参数,参数
  Object arguments,
 }) {
  return Navigator.of(context).pushNamed<T>(routeName, arguments: arguments);
}

使用方式如下:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
      routes: {
        "/first" : (context)=> FirstPage(),
      },
    );;
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("HomePage"),
      ),
      body: Builder(
        builder: (BuildContext context){
          return Container(
            color: Colors.yellow,
            child: Center(
              child: RaisedButton(
                child: Text("下一页"),
                onPressed: (){
                  Navigator.pushNamed(context, "/first");
                },
              ),
            ),
          );
        },
      ),
      endDrawer: Drawer(),
    );
  }
}

class FirstPage extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("FirstPage"),
      ),
      body: Center(
        child: RaisedButton(
          child: Text("上一页"),
          onPressed: (){
            Navigator.pop(context);
          },
        ),
      ),
    );
  }
}

因为在 home 中设置了首页,所以在 routes 中不需要设置 / 来表示首页,home 等同于 /

如果涉及到页面传值,正向传值如果使用 Navigator.push() ,可以使用被传递参数的 Widget 的构造方法,使用Navigator.pushNamed() ,可以使用其第三个参数 arguments 进行参数设置。 反向可以使用 Navigator.pop 的参数进行设置。如下:

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("HomePage"),
      ),
      body: Builder(
        builder: (BuildContext context){
          return Container(
            color: Colors.yellow,
            child: Center(
              child: RaisedButton(
                child: Text("下一页"),
                onPressed: (){
                 //使用push
                 Navigator.push(context, MaterialPageRoute(
                   builder: (context) => FirstPage("hike"),
                   fullscreenDialog: false,
                 )
                 ).then((value){
                   print(value);
                 });
                },
              ),
            ),
          );
        },
      ),
      endDrawer: Drawer(),
    );
  }
}

class FirstPage extends StatelessWidget {

  FirstPage(this.userName);
  final String userName;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("FirstPage"),
      ),
      body: Center(
        child: RaisedButton(
          child: Text("上一页 名字为:$userName"),
          onPressed: (){
            Navigator.pop(context, "返回给HomePage的值");
          },
        ),
      ),
    );
  }
}
class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("HomePage"),
      ),
      body: Builder(
        builder: (BuildContext context){
          return Container(
            color: Colors.yellow,
            child: Center(
              child: RaisedButton(
                child: Text("下一页"),
                onPressed: () async {
                 final result = await Navigator.pushNamed(context, "/first", arguments: <String, String>{
                    "name" : "hike",
                    "age" : "20",
                  });
                 print(result);
                },
              ),
            ),
          );
        },
      ),
      endDrawer: Drawer(),
    );
  }
}

class FirstPage extends StatelessWidget {

  @override
  Widget build(BuildContext context) {

    RouteSettings setting = ModalRoute.of(context).settings;

    final Map args = ModalRoute.of(context).settings.arguments;
    print(setting.name);

    return Scaffold(
      appBar: AppBar(
        title: Text("FirstPage"),
      ),
      body: Center(
        child: RaisedButton(
          child: Text("上一页"),
          onPressed: (){
            Navigator.pop(context, <String>["hike", "nick"]);
          },
        ),
      ),
    );
  }
}

在正向传值中,使用 Navigator.pushNamed() 方法时,参数 arguments 参数为 Object 类型,所以可以定义任意类型参数,也可以使用 class 等包装参数进行传递。当在接收参数页面接收参数时,使用 ModalRoute.of 进行获取,其返回一个带有参数的当前路由。

在反向传值时,当调用 Navigator.pop() 时,会将其中的参数包装到该方法返回的 Feature 对象中。后续文章会详细介绍。可以查看官方说明文档:https://flutter.dev/docs/cookbook/navigation/returning-data

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容