Flutter控件(2)

转载: http://blog.chengyunfeng.com/?p=1041

Flutter 控件之 Routes 和 Navigator

一个 App 通常会有多个界面,每个界面实现不同的功能,并在多个界面之间跳转。在 Flutter 中多个界面的跳转是通过 Navigator 来实现的。

在 Flutter 中定义了一个 Overlay Widget 用来管理多个界面,Overlay 里面使用 Stack 来显示当前的界面。通常不直接和 Overlay 打交道,而是使用 WidgetsApp 或者 MaterialApp 中的 Navigator 来管理界面。

比如在示例项目中https://github.com/goodev/learn_flutter 9.refactor 使用了 MaterialApp 的 routes 来定义多个界面以及每个界面的 key。然后使用 Navigator.pushNamed(context, routeName); 来跳转到具体的界面。

所以在 MaterialApp 中多页面跳转主要有两个任务。

定义 routes

routes 是 MaterialApp 中的一个属性,定义了全局的界面和每个界面的 key。在 Navigator 中使用 key 来指定跳转到具体的界面。 routes 的类型为 Map<String, WidgetBuilder>,WidgetBuilder 是一个方法定义,该方法返回一个 Widget。

使用 Navigator

通常使用 Navigator.push 和 Navigator.pop 来显示一个界面和删除一个当前显示的界面。 可以把 Navigator 当做一个堆栈,里面每个 item 都是一个界面,如果要显示一个界面,则使用 Navigator.push 把界面压到堆栈中,最上面的界面就是用户可见的界面;如果要移除最上面的界面,只需要调用 Navigator.pop 从堆栈中移除。

Navigator.push 的参数为 Route,一般在 MaterialApp 中使用 MaterialPageRoute.在 MaterialPageRoute 中定义了 Route 所代表的界面的 Widget 信息。

如果使用 routes 定义了全局的路由信息,则可以使用 Navigator.pushNamed 函数来显示一个具体的界面。

定义各种路由

在 Flutter 中,像 对话框、菜单、Dropdown 下拉选项、BottomSheet 等都是通过显示一个 Route 实现的。在 Flutter 中有三种路由:PopupRouteModalRoute, 和 PageRoute。 使用这些 路由可以实现各种弹出界面的情况。


Flutter控件之BottomNavigationBar FloatingActionButton

FloatingActionButton

FloatingActionButton(FAB)控件是一个纸墨设计中定义的FAB按钮。用来显示界面上的主要功能。

FloatingActionButton具有如下主要属性:

  • child:FAB中的子Widget
  • tooltip:长按FAB所显示的提示文字
  • backgroundColor:FAB的背景颜色
  • onPressed:点击FAB的回调函数
  • heroTag:应用到Hero Widget上的标签,用来做界面切换动画的
  • mini:只能FAB样式是默认样式还是迷你样式
  • 海拔和突出高度

FAB一般使用在Scaffold的floatingActionButton属性中。在示例应用中默认已经添加了一个FAB控件了。

BottomNavigationBar和BottomNavigationBarItem

BottomNavigationBar是[纸墨设计中的底部导航栏](https://material.io/guidelines/components/bottom-navigation.html)的实现,里面的每个项目都是一个BottomNavigationBarItem控件。

BottomNavigationBar有如下属性:

  • items:BottomNavigationBarItem列表,包含了导航栏中的按钮
  • onTap:点击里面的按钮的回调函数,参数为当前点击的按钮索引
  • currentIndex:当前所高亮的按钮索引
  • type:BottomNavigationBarType中定义的类型,有固定和移位两种类型
  • fixedColor:如果类型类型为fixed,则通过fixedColor设置选中item的颜色
  • iconSize:BottomNavigationBarItem中图标的大小

BottomNavigationBarItem有如下属性:

  • icon:图标widget,一般为Icon
  • title:标题widget,一般为Text
  • backgroundColor:item的背景颜色

BottomNavigationBar一般使用在Scaffold的bottomNavigationBar属性。

Scaffold还要另外一个属性persistentFooterButtons和bottomNavigationBar是有区别的,虽然都是在屏幕下方显示一些按钮,但是是persistentFooterButtons是纸墨设计中定义的固定在界面底部的常用按钮,而不是导航按钮。

persistentFooterButtons中是一个小部件列表,通常使用FlatButton。

下面的示例代码演示和如何使用persistentFooterButtons和bottomNavigationBar :( 
请注意,下面只是演示,在一般的项目中,这两个属性不会同时使用!!)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

<br />    final List<FlatButton> footerButtons = <FlatButton>[

      new FlatButton(

        child: new Text("OK"),

        onPressed: () => {},

      ),

      new FlatButton(

        child: new Text("CANCEL"),

        onPressed: () => {},

      ),

    ];

 

    final BottomNavigationBar botNavBar = new BottomNavigationBar(

      items: <BottomNavigationBarItem>[

        new BottomNavigationBarItem(

          icon: new Icon(Icons.access_alarm),

          title: new Text('Alarm'),

          backgroundColor: Colors.deepPurple[500],

        ),

        new BottomNavigationBarItem(

          icon: new Icon(Icons.save),

          title: new Text('Save'),

          backgroundColor: Colors.deepOrange[500],

        ),

        new BottomNavigationBarItem(

          icon: new Icon(Icons.cloud),

          title: new Text('Cloud'),

          backgroundColor: Colors.teal[500],

        ),

        new BottomNavigationBarItem(

          icon: new Icon(Icons.favorite),

          title: new Text('Favorites'),

          backgroundColor: Colors.indigo[500],

        )

      ],

      currentIndex: _currentIndex,

      type: BottomNavigationBarType.shifting,

      onTap: (int index) {

        setState(() {

          _currentIndex = index;

        });

      },

    );

 

    // This method is rerun every time setState is called, for instance

    // as done by the _incrementCounter method above.

    // The Flutter framework has been optimized to make rerunning

    // build methods fast, so that you can just rebuild anything that

    // needs updating rather than having to individually change

    // instances of widgets.

    return new Scaffold(

      bottomNavigationBar: botNavBar,

      persistentFooterButtons: footerButtons,

 

实现的效果图如下:

图片



Flutter 控件之 Drawer DrawerHeader 和 UserAccountsDrawerHeader

Drawer

在之前介绍 Scaffold 里面的 drawer 属性通常是一个 Drawer 对象。 Drawer 指的是纸墨设计中的导航侧边栏. Drawer 是从应用边缘拉出的一个导航面板。

如果没有设置 AppBar 的 leading 属性,则当使用 Drawer 的时候会自动显示一个 IconButton 来告诉用户有侧边栏(在 Android 上通常是显示为三个横的图标)。

Drawer 有两个属性,一个是设置 z 轴的 elevation;一个是设置 Drawer 内容的 child 属性。

Drawer 的内容通常是一个 ListView,里面包含一些设置项。而在 ListView 最上面通常会有个 DrawerHeader 来设置当前用户的基本信息,最常用的一个具体的 DrawerHeader 是 UserAccountsDrawerHeader 。

DrawerHeader

DrawerHeader 是 Drawer 最上方用来显示基本信息的控件。有如下属性:

  • decoration:header 区域的 decoration,通常用来设置背景颜色或者背景图片
  • duration 和 curve:如果 decoration 发生了变化,则会使用 curve 设置的变化曲线和 duration 设置的动画时间来做一个切换动画
  • child: Header 里面所显示的内容控件
  • padding: Header 里面内容控件的 padding 值,如果 child 为null,则这个值无效

如果想在 DrawerHeader 中显示用户账户信息,比如类似于 Gmail 的 联系人头像、用户名、Email 等信息,则可以使用 UserAccountsDrawerHeader 这个特殊的 DrawerHeader。

UserAccountsDrawerHeader

UserAccountsDrawerHeader 可以设置用户头像、用户名、Email 等信息,显示一个符合纸墨设计规范的 drawer header。

  • currentAccountPicture:用来设置当前用户的头像
  • accountName:当前用户的名字
  • accountEmail:当前用户的 Email
  • onDetailsPressed: 当 accountName 或者 accountEmail 被点击的时候所触发的回调函数,可以用来显示其他额外的信息
  • otherAccountsPictures:用来设置当前用户的其他账号的头像

DrawerItem

Drawer 中每个菜单项。有下面几个属性:

  • icon 配置菜单项的图标和图标尺寸、颜色
  • child 具体的菜单项内容
  • onPressed 当点击菜单项的时候所触发的回调函数
  • selected 当前菜单项是否选中了

比如下面的代码设置了 drawer 中的 Header 和 DrawerItem:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

    return new Scaffold(

      drawer: new Drawer(

        child: new ListView(

          children: <Widget>[

            new UserAccountsDrawerHeader(

              accountName: new Text('User Name'),

              accountEmail: new Text('[email protected]'),

              currentAccountPicture:

                  new CircleAvatar(backgroundImage: new AssetImage(_kAsset0)),

              otherAccountsPictures: <Widget>[

                new CircleAvatar(backgroundImage: new AssetImage(_kAsset1)),

                new CircleAvatar(backgroundImage: new AssetImage(_kAsset2)),

              ],

              onDetailsPressed: () {},

            ),

            new ClipRect(

              child: new DrawerItem(

                icon: new CircleAvatar(child: new Text("A")),

                child: new Text('Drawer item A'),

                onPressed: () => {},

              ),

            ),

          ],

        ),

      ),

所实现的效果如下:

image


Flutter控件之文本和基本的容器

文本

文件控件是用来显示一段文本的,使用方式如下:

1

2

3

4

5

6

7

8

9

new Text(

  'Flutter is a mobile app SDK .',

  style: new TextStyle(fontSize: 20.0, color: Colors.teal[500]),

  softWrap: true,

  overflow: TextOverflow.ellipsis,

  maxLines: 3,

  textAlign: TextAlign.left,

),

 

上面展示了文本控件的主要属性:要显示的文字内容,文字的样式,softWrap指定是否可以换行,maxLines指定最多显示多少行,当文字内容超过了maxLines指定的行数的时候,溢出用来指定超出文本的表示方式,是截断文本啊还是用三个点显示等,textAlign可以用来指定文本水平对齐方式。

其中当softWrap为假时候,说明不允许换行,这个时候相当于maxLines为1。

文字的样式TextStyle可以设置文字字体类型,大小,颜色,行高,字间距等和文本相关的选项。

富文本

文本只能显示一种样式的文字,如果你想在一段文字中显示多种样式 - 类似于Android里面的SpannableString - 的话,就需要使用RichText了。

如果你查看Text的源代码的话,会发现Text类的构建函数返回了一个RichText:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

  @override

  Widget build(BuildContext context) {

    final DefaultTextStyle defaultTextStyle = DefaultTextStyle.of(context);

    TextStyle effectiveTextStyle = style;

    if (style == null || style.inherit)

      effectiveTextStyle = defaultTextStyle.style.merge(style);

    return new RichText(

      textAlign: textAlign ?? defaultTextStyle.textAlign,

      softWrap: softWrap ?? defaultTextStyle.softWrap,

      overflow: overflow ?? defaultTextStyle.overflow,

      textScaleFactor: textScaleFactor ?? MediaQuery.of(context).textScaleFactor,

      maxLines: maxLines ?? defaultTextStyle.maxLines,

      text: new TextSpan(

        style: effectiveTextStyle,

        text: data

      )

    );

  }

 

所以可以看出,Text只是使用一种样式的RichText而已。

RichText中的文本使用TextSpan来定义,而每个TextSpan中包含了文本内容和文本样式以及一个子TextSpan列表。

比如在示例项目中用Text来显示按钮被点击的次数,则可以修改为用RichText来表示:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

new RichText(

    text: new TextSpan(

        text: 'Button tapped ',

        style: new TextStyle(

            inherit: true, fontSize: 32.0, color: Colors.black),

        children: <TextSpan>[

          new TextSpan(

              text: '$_counter',

              style: new TextStyle(

                  fontWeight: FontWeight.bold,

                  color: Colors.amber[500])),

          new TextSpan(text: ' time'),

          new TextSpan(

              text: _counter == 1 ? '' : 's',

              style: new TextStyle(

                  fontWeight: FontWeight.w200,

                  color: Colors.cyan[500])),

          new TextSpan(text: '.'),

        ],

    ),

),

 

请注意上面的RichText的文字属性的取值为一个TextSpan,而这个TextSpan里面又包含了一个children集合。

图片

如果要显示图片,则需要使用图像控件。图像可以显示文件,资源包或者网络图片,当图标加载完后会在界面显示。

图片具有宽度,高度,颜色过滤器(类似于Android中的色调),适合模式,重复模式等属性。和Android中ImageView的属性差不多。

1

2

3

// 加载一个网络图片

new Image.network('https://flutter.io/images/flutter-mark-square-100.png')

 

你可能发现了上面的文字或者Image都没有设置Padding(留白)和Margin(边距)值的属性,也没有设置背景颜色的属性。如果你希望设置这些属性则需要使用下面的几个小部件。

填充

Padding是用来给一个控件设置padding值的.padding属性值是EdgeInsets对象,可以指定上下左右的边距值;而child属性是一个Widget对象,是需要留白的那个控件。

比如,下面就用Padding在Text下边设置了8px的边距:

1

2

3

4

5

6

7

8

9

10

11

12

new Padding(

    padding: new EdgeInsets.only(bottom: 8.0),

    child: new Text(

        'Flutter 是一个用一套代码就可以构建高性能安卓和苹果应用的移动应用 SDK。 ',

        style: new TextStyle(fontSize: 28.0),

        softWrap: true,

        overflow: TextOverflow.ellipsis,

        maxLines: 2,

        textAlign: TextAlign.left,

    ),

);

 

 

如果要给Widget设置Margin或者背景颜色,就需要使用Container了。

容器

和Padding相比,Container的属性要多一些:
- alignment设置子控件的布局位置
- padding设置子控件的padding值
- margin设置子控件的margin value 
- transform设置子控件的矩阵变换,比如在显示的时候,可以旋转一个控件
- decoration设计
子控件背面所绘制的装饰
- constraintsDecoration设置子控件上面所绘制的装饰- constraints设置子控件尺寸的约束条件,比如长宽的最大值,最小值
- child设置子控件对象

例如,下面在Image上设置了边距,背景颜色,旋转以及最小宽度等:

1

2

3

4

5

6

7

8

9

10

11

new Container(

    padding: new EdgeInsets.only(bottom: 8.0),

    decoration:

    new BoxDecoration(backgroundColor: Colors.grey[200]),

    child: new Image.network(

        'https://flutter.io/images/flutter-mark-square-100.png'),

    margin: new EdgeInsets.only(bottom: 8.0),

    transform: new Matrix4.rotationZ(100.0),

    constraints: new BoxConstraints(minHeight: 150.0),

);

 

注意:(目前)并没有Margin这个控件。在Container中也可以设置padding。如果只是设置一个Widget的padding则可以使用Padding类,如果还需要同时设置背景,margin等属性则可以使用Container类。

中央

如果想把一个Widget居中显示,则可以用中控制。中心控件顾名思义就是把子控件居中显示,可以设置中央控件的宽高因子,如果不设置,则中心会占用尽可能的控件。

列和行

如果要把多个控件放一起显示为一列,则需要使用列类,
如果要把多个控件放一起显示为一行,则需要使用行类。
例如下面使用列把多个文本组合一起显示:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

new Column(

  mainAxisSize: MainAxisSize.min,

  children: <Widget>[

    new Text(

      'Flutter is a mobile app SDK for building high-performance, high-fidelity, apps for iOS and Android, from a single codebase.',

      style: new TextStyle(fontSize: 20.0, color: Colors.teal[500]),

      softWrap: true,

      overflow: TextOverflow.ellipsis,

      maxLines: 3,

      textAlign: TextAlign.left,

    ),

    new Text(

      'Flutter 是一个用一套代码就可以构建高性能安卓和苹果应用的移动应用 SDK。 ',

      style: new TextStyle(fontSize: 28.0),

      softWrap: true,

      overflow: TextOverflow.ellipsis,

      maxLines: 2,

      textAlign: TextAlign.left,

    ),

  ],

);

 

Column和Row有一样的属性:

  • mainAxisAlignment设置主轴方向上的对齐方式,比如现在列高度为500px,里面包含两个子控件高度分别为100px,那么还剩余300px的空余空间,如果指定为MainAxisAlignment.spaceAround值,则剩余的300px会分为三份,在两个子控件上下和中间各100px的空间。
  • mainAxisSize设置主轴方向所占的高度或者宽度(Column就是指高度)
  • crossAxisAlignment设置副轴方向上的对齐方式,比如对于列可以使用CrossAxisAlignment.center来设置里面的子控件水平居中对齐
  • children是里面的一些子控件列表
发布了44 篇原创文章 · 获赞 15 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/m0_37039192/article/details/90735137