上一节我们介绍了Row, Column, Image, Text
四个基础组件,这一节我们来看看下面几个组件。
Icon
Icon就是图标,字体图标,矢量图。在web前端中我们使用图标可以自己定义字体与SVG,使用阿里图标上面的图标。在Flutter中,google则为我们集成了一些常用的图标。
看看Icon的属性有哪些
1 2 3 4 5 6 7 8
| const Icon( this.icon, { Key key, this.size, this.color, this.semanticLabel, this.textDirection, }) : super(key: key);
|
我们能够用到的就是 size
与 color
两个属性,第一个是字体。使用Icons
类。下面有很多图标。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Icon( Icons.speaker, color: Colors.red, size: 100, ),Icon( Icons.star_half, color: Colors.blue, size: 100, ),Icon( Icons.volume_up, color: Colors.red, size: 100, ) ], )
|
当然,这些都是 Flutter material 中自带的一些图标,如果我们需要自己定义图标怎么弄呢?这也是可以的,就像我们在web中使用 iconfont 一样。
1 2 3 4 5 6 7 8 9
| Icon( MyIcons.weChat, color: Colors.green, size: 100, ),Icon( MyIcons.qq, color: Colors.blue, size: 100, )
|
上面的代码中出现了 MyIcons
这个类。哪里来的呢?其实这个是我们自己创建的类,怎么创建的来看看。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import 'package:flutter/material.dart';
class MyIcons { static const IconData weChat = const IconData( 0xe63d, fontFamily: "MyIcons", matchTextDirection: true );
static const IconData qq = const IconData( 0xe6ca, fontFamily: "MyIcons", matchTextDirection: true ); }
|
MyIcons
是我们自己创建的类,里面定义了两个Icon,一个名字是weChat
,另一个是qq
。使用的是IconData
这个类创建,里面有三个参数。Icon的Unicode
编码,这个在阿里图标上表示在这里
我们把上面的 &# 换成 0 就可以了。
fontFamily呢?是我们自己定义的字体
字体呢就是我们在阿里图标上面下载下来的文件。
这些就是关于 Icon
的简单介绍。
其实这就是一个按钮,一个凸起的材质矩形的按钮。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| const RaisedButton({ Key key, @required VoidCallback onPressed, ValueChanged<bool> onHighlightChanged, ButtonTextTheme textTheme, Color textColor, Color disabledTextColor, Color color, Color disabledColor, Color highlightColor, Color splashColor, Brightness colorBrightness, double elevation, double highlightElevation, double disabledElevation, EdgeInsetsGeometry padding, ShapeBorder shape, Clip clipBehavior = Clip.none, MaterialTapTargetSize materialTapTargetSize, Duration animationDuration, Widget child, })
|
属性有很多,能用到的也就那么几个,大部分都是使用的默认值。
下面是App中的源码
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 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
| child: Column( children: <Widget>[ RaisedButton( onPressed: () {}, child: Text("textColor文本的颜色,color背景颜色,highlightColor按钮按下的颜色"), textColor: Color(0xffff0000), color: Color(0xfff1f1f1), highlightColor: Color(0xff00ff00), ), RaisedButton( onPressed: () {}, child: Text("disabledTextColor禁用时文本颜色,disabledColor禁用时背景颜色"), disabledTextColor: Color(0xff999999), disabledColor: Color(0xffff0000), ), RaisedButton( onPressed: () {}, child: Text("splashColor水波的颜色,disabledColor禁用时背景颜色"), splashColor: Color(0xffff0000), ), RaisedButton( onPressed: () {}, child: Text("colorBrightness按钮主题高亮 Brightness.light"), colorBrightness: Brightness.light, ), RaisedButton( onPressed: () {}, child: Text("colorBrightness按钮主题高亮 Brightness.dark"), colorBrightness: Brightness.dark, ), Container( margin: EdgeInsets.only(top: 20.0), child: RaisedButton( onPressed: () {}, child: Text( "elevation按钮下面的阴影,highlightElevation高亮时候的阴影,disabledElevation按下的时候的阴影"), elevation: 5.0, ), ), Container( margin: EdgeInsets.only(top: 20.0), child: RaisedButton( onPressed: () {}, child: Text( "elevation按钮下面的阴影,highlightElevation高亮时候的阴影,disabledElevation按下的时候的阴影"), highlightElevation: 5, ), ), Container( margin: EdgeInsets.only(top: 20.0), child: RaisedButton( onPressed: () {}, child: Text( "elevation按钮下面的阴影,highlightElevation高亮时候的阴影,disabledElevation按下的时候的阴影"), disabledElevation: 5.0, ), ), RaisedButton( onPressed: () {}, child: Text( "onHighlightChanged 水波纹高亮变化回调,按下返回true,抬起返回false"), onHighlightChanged: (bool b) => Fluttertoast.showToast( msg: '$b', toastLength: Toast.LENGTH_LONG, fontSize: 12 ), ), RaisedButton( onPressed: () => Fluttertoast.showToast( msg: '你点击了按钮', toastLength: Toast.LENGTH_LONG, fontSize: 12 ), child: Text("onPressed点击事件"), ), ], )v
|
就像上面的代码中看到的,除了onPressed
是必选以外,其余的属性基本上用的不是特别的多,有一些没有涉及到的属性,有兴趣可以自己下来了解。
Scaffold
之前简单提到过Scaffold
,因为我们用到这个Widget的时候实在是太多了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| const Scaffold({ Key key, this.appBar, this.body, this.floatingActionButton, this.floatingActionButtonLocation, this.floatingActionButtonAnimator, this.persistentFooterButtons, this.drawer, this.endDrawer, this.bottomNavigationBar, this.bottomSheet, this.backgroundColor, this.resizeToAvoidBottomPadding, this.resizeToAvoidBottomInset, this.primary = true, this.drawerDragStartBehavior = DragStartBehavior.start, this.extendBody = false, })
|
Scaffold
可以说是一个容器,里面可以设置很多地方的Widget,比如AppBar
,drawer
,bottomNavigationBar
等等。下面的每一部分又有自己单独的设置方法。还是来看看怎么使用。
AppBar
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| AppBar({ Key key, this.leading, this.automaticallyImplyLeading = true, this.title, this.actions, this.flexibleSpace, this.bottom, this.elevation, this.shape, this.backgroundColor, this.brightness, this.iconTheme, this.actionsIconTheme, this.textTheme, this.primary = true, this.centerTitle, this.titleSpacing = NavigationToolbar.kMiddleSpacing, this.toolbarOpacity = 1.0, this.bottomOpacity = 1.0, })
|
来看看AppBar中每一部分的布局,下面图片来自Flutter官网
leading
正如上面的图片中看到的,这个属性可以设置AppBar左侧的内容
1 2 3 4 5 6 7 8 9
| appBar: AppBar( title: Text('AppBar'), leading: IconButton( onPressed: () => {}, icon: Icon( Icons.nature ), ), ),
|
这里设置的是一个 nature
图标,当然,你也可以设置其他的图标,或者是其他的Widget,文字,图片等等。
automaticallyImplyLeading
官方的解释为
Controls whether we should try to imply the leading widget if null
我理解为:如果没有设置leading
属性,是否需要将leading默认设置为null。左右可能就是做一个站位。默认是true,使用默认值就行。
title
标题。不用多说。
actions
正如上面的图片中看到的,这个属性可以设置AppBar中右侧的显示。上面图片中显示了三个,说明这是一个Widget List。
1
| actions: <Widget>[Icon(Icons.book), Icon(Icons.satellite),Center(child: Text('action'))]
|
flexibleSapce
这个最上面的图也有解释。整个AppBar相当于采用flex布局,flexibleSapce空间属于AppBar中除了整个空间。包含了leading,title以及bottom区间。值是一个Widget。
为什么这样说呢?
1 2 3 4 5
| flexibleSpace: Container( color: Colors.green, child: Text("flexibleSpace") )
|
上面的代码中我们把alignment
属性注释掉了,结果如下
接着我们取消注释
这就是原因。不过这个属性好像不怎么用得着啊。整个AppBar可能用得多的地方就是leading,title和actions了吧。
bottom
一个 AppBarBottomWidget 对象,通常是 TabBar。用来在 Toolbar 标题下面显示一个 Tab 导航栏
1 2 3 4
| bottom: PreferredSize( child: Text('bottom区间'), preferredSize: Size.fromHeight(100), ),
|
你还可以在bottom中添加TabBar
,这样就更加充分利用了bottom这个属性
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 54 55 56 57 58 59 60 61 62 63 64 65 66
| import 'package:flutter/material.dart';
void main() => runApp(ScaffoldInfo());
class ScaffoldInfo extends StatelessWidget { ScaffoldInfo({Key key, this.title}) : super(key: key); final String title; @override Widget build(BuildContext context){ return Scaffold( appBar: AppBar( title: Text(title), ), bottomNavigationBar: Text('1'), body: Container( padding: const EdgeInsets.fromLTRB(20, 10, 20, 10), child: DefaultTabController( length: 6, child: Scaffold( appBar: AppBar( title: Text('AppBar'), leading: IconButton( onPressed: () => {}, icon: Icon( Icons.nature ), ), automaticallyImplyLeading: true, actions: <Widget>[Icon(Icons.book), Icon(Icons.satellite),Center(child: Text('action'))], flexibleSpace: Container( color: Colors.green, alignment: Alignment.center, child: Text("flexibleSpace") ), bottom: TabBar( isScrollable: true, tabs: <Widget>[ Tab(text: 'Tab 1'), Tab(text: 'Tab 2'), Tab(text: 'Tab 3'), Tab(text: 'Tab 4'), Tab(text: 'Tab 5'), Tab(text: 'Tab 6'), ], ), backgroundColor: Colors.red, brightness: Brightness.dark, ), body: TabBarView( children: <Widget>[ Center(child: Text('Tab 1')), Center(child: Text('Tab 2')), Center(child: Text('Tab 3')), Center(child: Text('Tab 4')), Center(child: Text('Tab 5')), Center(child: Text('Tab 6')), ], ) ), ) ) ); } }
|
这里收涉及到了TabBar
以及TabBarView
两个类。这里不多讲,需要注意的是这两个都需要设置一个controller
属性,如果不设置,可以使用DefaultTabController
创建默认的容器。
elevation
这个属性是设置整个AppBar的阴影的大小,值是一个double
。
下面是设置了elevation: 20,
的前后对比,还是使用默认的就可以了
backgroundColor
AppBar的背景色。如果flexibleSapce
设置了背景色,这个背景色将会被覆盖。
brightness
AppBar的主题,有两个选择,Brightness.dark
或者 Brightness.light
。
centerTitle
标题是否居中显示,默认值根据不同的操作系统,显示方式不一样。安卓可能在左侧,IOS则是居中。
body
主题内容区域,这个区域就不介绍了,body可以设置各种Widget。
这是一个浮动按钮,注意参数就是一个child(一般是一个Icon),其次就是 onPressed 点击事件。其余的可以使用默认属性,或者你修改一下背景色等等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const FloatingActionButton({ Key key, this.child, this.tooltip, this.foregroundColor, this.backgroundColor, this.heroTag = const _DefaultHeroTag(), this.elevation, this.highlightElevation, this.disabledElevation, @required this.onPressed, this.mini = false, this.shape, this.clipBehavior = Clip.none, this.materialTapTargetSize, this.isExtended = false, })
|
在右下角增加一个浮动按钮
1 2 3 4
| floatingActionButton: FloatingActionButton( child: Icon(Icons.add), onPressed: () => {}, ),
|
前面讲的是设置一个浮动按钮,这个浮动按钮的位置默认是在右下角。如果是要设置这个浮动按钮的位置,就需要用到FloatingActionButtonLocation
1
| floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
|
在footer设置一系列的button,值是一个Widget list
1 2 3 4 5
| persistentFooterButtons: <Widget>[ Icon(Icons.satellite), Icon(Icons.save), Icon(Icons.share), ],
|
在设置bottomNavigationBar
的时候,可能页面会很丑,我们可以放弃使用这个属性
drawer 与 endDrawer
这两个都是抽屉盒子,drawer
是从左往右滑动的时候出现,endDrawer
是从右往左画的时候出现
1 2 3 4 5 6
| drawer: Container( child: Text('drawer'), ), endDrawer: Container( child: Text('endDrawer'), ),
|
具体的内容还要自己实现。
bottomNavigationBar
在底部设置一个导航组件
1 2 3 4 5 6 7 8 9 10 11
| bottomNavigationBar: BottomAppBar( shape: CircularNotchedRectangle(), child: Row( children: [ IconButton(icon: Icon(Icons.home), onPressed: () => {}), SizedBox(), IconButton(icon: Icon(Icons.business), onPressed: () => {}), ], mainAxisAlignment: MainAxisAlignment.spaceAround, ), ),
|
可以看到这样出来的效果很丑,这是因为我们之前设置了persistentFooterButtons
这个属性,占据了上面一部分空间。一般这个属性我们都不会设置的,我们把persistentFooterButtons
属性注释掉在来看看。
这样看起来好看多了。
bottomSheet
底部划出组件,一般很少直接使用,而是使用showModalBottomSheet
弹出,比如从底部弹出分享框。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| floatingActionButton: FloatingActionButton( child: Icon(Icons.add), onPressed: () => showModalBottomSheet( context: context, builder: (BuildContext context) { return new Container( height: 300.0, child: Text('弹出的东东'), ); }, ).then((val) { print(val); }), ),
|
点击 + 按钮会弹出这个
总结
Flutter的基础的组件就讲到这里,涉及到的大都是常用的组件,部分东西没有涉及到或者说没有详细说明,可能是因为我认为不用过多说明,可能是因为没有太多时间,也可能是因为我自己也不看明白,如果你不懂,我们可以一起探讨,在评论框留言,有问题我们一起探讨。
在下面的课程中,我们将会介绍一些Flutter的中高级的Widget。