上一节我们介绍了Row, Column, Image, Text
四个基础组件,这一节我们来看看下面几个组件。
Icon就是图标,字体图标,矢量图。在web前端中我们使用图标可以自己定义字体与SVG,使用阿里图标上面的图标。在Flutter中,google则为我们集成了一些常用的图标。
看看Icon的属性有哪些
const Icon(
this.icon, {
Key key,
this.size,
this.color,
this.semanticLabel,
this.textDirection,
}) : super(key: key);
我们能够用到的就是 size
与 color
两个属性,第一个是字体。使用Icons
类。下面有很多图标。
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 一样。
Icon(
MyIcons.weChat,
color: Colors.green,
size: 100,
),Icon(
MyIcons.qq,
color: Colors.blue,
size: 100,
)
上面的代码中出现了 MyIcons
这个类。哪里来的呢?其实这个是我们自己创建的类,怎么创建的来看看。
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
的简单介绍。
其实这就是一个按钮,一个凸起的材质矩形的按钮。
const RaisedButton({
Key key,
@required VoidCallback onPressed, // 按钮点击事件,必选
ValueChanged<bool> onHighlightChanged, //水波纹高亮变化回调,按下返回true,抬起返回false 使用默认值就可以
ButtonTextTheme textTheme, //按钮的主题
Color textColor, //按钮文字的颜色
Color disabledTextColor, //按钮禁用时候文字颜色
Color color, //按钮背景色
Color disabledColor, //按钮禁用时候背景色
Color highlightColor, // 点击或者toch控件高亮的时候显示在控件上面,水波纹下面的颜色
Color splashColor, //水波纹的颜色
Brightness colorBrightness, //按钮主题高亮
double elevation, //按钮下面的阴影
double highlightElevation, //高亮时候的阴影
double disabledElevation, //禁用时候的阴影
EdgeInsetsGeometry padding,
ShapeBorder shape, //设置形状
Clip clipBehavior = Clip.none,
MaterialTapTargetSize materialTapTargetSize,
Duration animationDuration,
Widget child, // 子元素,一般是文字,如果是icon,有专门的icon图标
})
属性有很多,能用到的也就那么几个,大部分都是使用的默认值。
下面是App中的源码
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
,因为我们用到这个Widget的时候实在是太多了。
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({
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官网
正如上面的图片中看到的,这个属性可以设置AppBar左侧的内容
appBar: AppBar(
title: Text('AppBar'),
leading: IconButton(
onPressed: () => {},
icon: Icon(
Icons.nature
),
),
),
这里设置的是一个 nature
图标,当然,你也可以设置其他的图标,或者是其他的Widget,文字,图片等等。
官方的解释为
Controls whether we should try to imply the leading widget if null
我理解为:如果没有设置leading
属性,是否需要将leading默认设置为null。左右可能就是做一个站位。默认是true,使用默认值就行。
标题。不用多说。
正如上面的图片中看到的,这个属性可以设置AppBar中右侧的显示。上面图片中显示了三个,说明这是一个Widget List。
actions: <Widget>[Icon(Icons.book), Icon(Icons.satellite),Center(child: Text('action'))]
这个最上面的图也有解释。整个AppBar相当于采用flex布局,flexibleSapce空间属于AppBar中除了整个空间。包含了leading,title以及bottom区间。值是一个Widget。
为什么这样说呢?
flexibleSpace: Container(
color: Colors.green,
// alignment: Alignment.center,
child: Text("flexibleSpace")
)
上面的代码中我们把alignment
属性注释掉了,结果如下
接着我们取消注释
这就是原因。不过这个属性好像不怎么用得着啊。整个AppBar可能用得多的地方就是leading,title和actions了吧。
一个 AppBarBottomWidget 对象,通常是 TabBar。用来在 Toolbar 标题下面显示一个 Tab 导航栏
bottom: PreferredSize(
child: Text('bottom区间'),
preferredSize: Size.fromHeight(100),
),
你还可以在bottom中添加TabBar
,这样就更加充分利用了bottom这个属性
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'),
],
),
// elevation: 20,
backgroundColor: Colors.red,
brightness: Brightness.dark,
// centerTitle: true,
),
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
创建默认的容器。
这个属性是设置整个AppBar的阴影的大小,值是一个double
。
下面是设置了elevation: 20,
的前后对比,还是使用默认的就可以了
AppBar的背景色。如果flexibleSapce
设置了背景色,这个背景色将会被覆盖。
AppBar的主题,有两个选择,Brightness.dark
或者 Brightness.light
。
标题是否居中显示,默认值根据不同的操作系统,显示方式不一样。安卓可能在左侧,IOS则是居中。
主题内容区域,这个区域就不介绍了,body可以设置各种Widget。
这是一个浮动按钮,注意参数就是一个child(一般是一个Icon),其次就是 onPressed 点击事件。其余的可以使用默认属性,或者你修改一下背景色等等。
const FloatingActionButton({
Key key,
this.child,
this.tooltip, // 长按时显示的提示
this.foregroundColor,
this.backgroundColor,
this.heroTag = const _DefaultHeroTag(), //hero效果使用的tag,系统默认会给所有FAB使用同一个tag,方便做动画效果
this.elevation,
this.highlightElevation,
this.disabledElevation,
@required this.onPressed,
this.mini = false,
this.shape,
this.clipBehavior = Clip.none,
this.materialTapTargetSize,
this.isExtended = false,
})
在右下角增加一个浮动按钮
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () => {},
),
前面讲的是设置一个浮动按钮,这个浮动按钮的位置默认是在右下角。如果是要设置这个浮动按钮的位置,就需要用到FloatingActionButtonLocation
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
在footer设置一系列的button,值是一个Widget list
persistentFooterButtons: <Widget>[
Icon(Icons.satellite),
Icon(Icons.save),
Icon(Icons.share),
],
在设置bottomNavigationBar
的时候,可能页面会很丑,我们可以放弃使用这个属性
这两个都是抽屉盒子,drawer
是从左往右滑动的时候出现,endDrawer
是从右往左画的时候出现
drawer: Container(
child: Text('drawer'),
),
endDrawer: Container(
child: Text('endDrawer'),
),
具体的内容还要自己实现。
在底部设置一个导航组件
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
属性注释掉在来看看。
这样看起来好看多了。
底部划出组件,一般很少直接使用,而是使用showModalBottomSheet
弹出,比如从底部弹出分享框。
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。