Flutter里有一个非常重要的核心理念:一切皆为组件,Flutter所有的元素皆有组件组成,比如一个布局元素、一个动画、一个装饰效果
无状态组件和有状态组件:
无状态组件(StatelessWidget)是不可变的,这意味着他们的属性不能改变,所有的值都是最终的。
有状态组件(StatefulWidget)持有的状态可能在Widget生命周期中发生变化。实现一个StatefulWidget至少需要两个类:
- 一个StatefulWidget类
- 一个State类。StatefulWidget类本身是不变的,但是State类在Widget生命周期中始终存在。使用setState方法来控制变量值的变化
第一部分:基础组件
① Container(容器组件)自身具备以下属性:
1.alignment:child对齐方式(AligenmentGeometry枚举值)
2.padding组件内边距(EdgeInsets.only/EdgeInsets.all)
3.color容器颜色
4.decoration装饰器,决定组件样式,不能跟color属性共用
5.width 宽度 (设置double.infinity可以强制在宽度上撑满)
6.height高度(设置double.infinity可以强制在高度上撑满)
7.margin外边距(EdgeInsets.only/EdgeInsets.all)
8.child 嵌套组件
②Image图片组件:
- Image()从ImageProvider获取图像
- Image.asset()加载资源图片
- Image.file()加载本地图片文件
- Image.network()加载网络图片
- Image.memory()加载Uint8List资源图片
主要属性:
1.width/height宽高
2.fit图片填充模式(BoxFit枚举值)
BoxFit.fill全图显示,显示可能拉伸,充满
BoxFit.contain全图显示,显示原比例,不需充满
BoxFit.cover显示可能拉伸,可能裁剪,充满
BoxFit.fitWidth显示可能拉伸,可能裁剪,宽度充满
BoxFit.fitHeight显示可能拉伸,可能裁剪,高度充满
BoxFit.none原始大小
BoxFit.scaleDown,跟contain差不多据说
3.color图片颜色
4.alignment控制图片的摆放位置:Alignment.bottomRight
③text文本组件
style文本样式(定义文本的字体大小、颜色、粗细等)
data:数据要显示的文本
maxLines:文本显示的最大行数
style:文本样式TextStyle
textSpan:TextSpan:文本块,TextSpan里可以包含文本内容及样式
④图标及按钮组件
4.1图标组件
主要属性:color—icon—size–style
主要图标组件:
IconButton可交互的Icon
Icons框架自带Icon集合
IconTheme Icon主题
ImageIcon 通过AssetImages或者其他图片显示Icon
4,2图标按钮组件
IconButton带有水波纹按压效果的图片按钮组件 带有回调函数onPressed
4.3图标凸起组件
RaisedButton,一个凸起的材质矩形按钮button,按下时带有触摸效果
主要属性 color、onPressed、child、enable
⑤列表组件ListView
1.0主要属性:
scrollDirection:Axis.vrtical/Axis.horizontal 竖直还是水平 默认竖直
padding:内边距
children:列表元素
2.0长列表组件
ListView.builder(
itemCount:items.length,
itemBuilder:(context,index){
return new ListTile(
leading:new Icon();
title:new text(),
);
}
);
3.0网格组件GridView
GridView.count 通过单行展示个数创建GridView
GridView.extent 通过最大宽度创建GridView
scrollDirection:滚动方向 Axis.vrtical/Axis.horizontal
padding:内边距
children:列表元素
crossAxisCount:每行元素数量
crossAxisSpacing:行间距
⑥表单组件
Form表单提交/TextFormField用户输入
Form:
autovalidate:是否自动提交表单
child:
onChanged:当TextFormField值改变时的回调函数
TextFormField:
autovalidate:自动验证值
initialValue:表单初始值
onSaved:当Form表单调用保存方法Save时回调的函数
validator:Form表单验证器
第二部分:Material Dedign风格组件
①APP结构和导航组件:
MaterialApp、Scaffold、AppBar、BottomNavigationBar、TabBar、Drawer
1.1、MaterialApp
代表使用纸墨设计风格的应用,里边包含了其所需要的基本控件,
包括以下属性:
title:应用程序的标题
theme:ThemeData应用主题
color:Color应用的主要颜色值即primary color
home:用来定义当前应用打开时所显示的界面
routes:定义应用中页面跳转规则(路由)
routes: <String, WidgetBuilder>{
"app": (BuildContext context) => new App(),
"/friends": (_) => new WebviewScaffold(
url: "https://www.baidu.com/",
appBar: new AppBar(
title: new Text("百度首页"),
),
withZoom: true,
withLocalStorage: true,
),
"search": (BuildContext context) => new Search(),
}
initialRoute:初始化路由,
onGenerateRoute:路由回调函数,当通过Navigator.of(context).pushName跳转路由在routes中找不到的时候,会调用改方法
onLocaleChanged:当系统修改语言的时候,会出发这个回调
1.2、脚手架组件Scaffold
实现了基本的Material Design布局。只要是在Material Design中定义过的单个界面显示的布局组件元素,都可以使用scaffold来绘制
基本属性如下:
appBar:显示在界面顶部的一个appbar
body:界面主要内容
floatingActionButton:一个功能按钮
drawer:侧边栏组件
bottomNavigationBar:显示在底部的导航栏按钮栏
backgroundColor:背景颜色
1.2.1、appBar
应用按钮组件有AppBar和SliverAppBar,他们是纸墨设计中的appbar,也就是Android中的toolbar,
AppBar和SliverAppBar都是继承自StatefulWidget类,都代表Toolbar,两者的区别在于AppBar位置是固定的,而后者是可以跟随内容滚动的。
常见属性:
leading:在标题前边显示的一个组件,在首页通常显示应用的logo,在其他页面通常显示为返回按钮
title:通常显示为当前页面的标题文字
actions:一个Widget列表,代表Toobar中所显示的菜单,对于常用菜单,通常使用IconButton来表示,对于不常用的菜单通常使用PopupMenuButton来显示为三个点,点击后弹出二级菜单。
bottom:通常是TabBar,用来在Toolbar标题下边显示一个tab导航栏
//toolbar中显示的菜单
actions: <Widget>[
IconButton(
icon: Icon(Icons.search),
onPressed: () {
showDialog<Null>(
context: context,
builder: (BuildContext context) {
return new AlertDialog(
title: Text("提示"),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text(
"是否要删除?",
),
Text("一旦删除数据不可恢复?")
],
),
),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text("确定")),
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text("取消"))
],
);
}).then((value) {
print(value);
});
},
tooltip: "搜索",
),
IconButton(
icon: Icon(Icons.add),
onPressed: () {},
tooltip: "添加",
),
//toolbar中显示的耳机菜单
PopupMenuButton(
itemBuilder: (BuildContext context) => <PopupMenuItem<String>>[
PopupMenuItem<String>(
child: Text("热度"),
value: "hot",
),
PopupMenuItem<String>(
child: Text("最新"),
value: "new",
),
],
onSelected: (String action) {
switch (action) {
case "hot":
print("hot");
break;
case "new":
print("new");
break;
}
},
//取消了pop二级菜单
onCanceled: () {
print("onCanceled");
},
),
]
//标题居中
centerTitle: true,
//appbar图标颜色等信息 表示颜色是黄色,不透明度是0.5,最大值是1;以及大小是30,默认的大小是24
iconTheme: IconThemeData(color: Colors.yellow, opacity: 0.5, size: 20),
//appbar背景色
backgroundColor: Color(0xffDE331F),
//控制状态栏的颜色,lignt 文字是灰色的,dark是白色的
brightness: Brightness.light,
textTheme:appbar上文字颜色
1.2.2、BottomNavigationBar底部导航条组件
currentIndex:当前索引
fixedColor:选中按钮的颜色
iconSize:按钮图标大小
items:底部导航条按钮集
ontap:按下某一个按钮回调事件,需要根据返回的索引设置当前索引
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _selectedIndex = 1; //当前选中项的索引
final _widgrtOptions = ["Index 0:信息", "Index 1:通信录", "Index 2:发现"];
//选择按下处理 设置当前索引为index值
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
@override
Widget build(BuildContext context) {
return new Scaffold(
//侧边栏Drawer
drawer: Drawer(
child: ListView(
children: <Widget>[
UserAccountsDrawerHeader(
accountName: new Text("李云龙"),
accountEmail: new Text("liyunlong.163.com"),
currentAccountPicture: new CircleAvatar(
backgroundImage: new AssetImage("images/look.jpg"),
),
decoration: new BoxDecoration(
//用一个BoxDecoration装饰器提供背景图片
image: new DecorationImage(
fit: BoxFit.fill,
// image: new NetworkImage('https://raw.githubusercontent.com/flutter/website/master/_includes/code/layout/lakes/images/lake.jpg')
//可以试试图片调取自本地。调用本地资源,需要到pubspec.yaml中配置文件路径
image: new ExactAssetImage('images/fengjing.jpg'),
),
),
onDetailsPressed: () {},
otherAccountsPictures: <Widget>[
new Container(
child: Image.asset("images/erweima.png"),
)
],
),
ListTile(
leading: new CircleAvatar(
child: Icon(Icons.color_lens),
),
title: Text("个性装扮"),
),
ListTile(
leading: new CircleAvatar(
child: Icon(Icons.photo),
),
title: Text("我的相册"),
),
ListTile(
leading: new CircleAvatar(
child: Icon(Icons.wifi),
),
title: Text("免流量特权"),
)
],
),
),
//头部元素 比如 左侧返回按钮 中间标题 右侧菜单
appBar: new AppBar(
title: Text("AppBar应用按钮示例"),
//标题居中
centerTitle: true,
//标题左侧按钮
leading: Icon(Icons.arrow_back),
//表示颜色是黄色,不透明度是0.5,最大值是1;以及大小是30,默认的大小是24
iconTheme: IconThemeData(color: Colors.yellow, opacity: 0.5, size: 20),
//appbar背景色
backgroundColor: Color(0xffDE331F),
brightness: Brightness.light,
//控制状态栏的颜色,lignt 文字是灰色的,dark是白色的
//toolbar中显示的菜单
actions: <Widget>[
IconButton(
icon: Icon(Icons.search),
onPressed: () {},
tooltip: "搜索",
),
IconButton(
icon: Icon(Icons.add),
onPressed: () {},
tooltip: "添加",
),
//toolbar中显示的耳机菜单
PopupMenuButton(
itemBuilder: (BuildContext context) => <PopupMenuItem<String>>[
PopupMenuItem<String>(
child: Text("热度"),
value: "hot",
),
PopupMenuItem<String>(
child: Text("最新"),
value: "new",
),
],
onSelected: (String action) {
switch (action) {
case "hot":
print("hot");
break;
case "new":
print("new");
break;
}
},
//取消了pop二级菜单
onCanceled: () {
print("onCanceled");
},
),
],
),
//视图内容部分
body: Center(
child: Text(
_widgrtOptions.elementAt(_selectedIndex),
),
),
//底部导航栏
bottomNavigationBar: BottomNavigationBar(
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(icon: Icon(Icons.chat), title: Text("信息")),
BottomNavigationBarItem(
icon: Icon(Icons.contacts), title: Text("通讯录")),
BottomNavigationBarItem(
icon: Icon(Icons.account_circle), title: Text("发现")),
],
currentIndex: _selectedIndex,
fixedColor: Colors.deepPurple,
onTap: _onItemTapped,
),
//添加FAB按钮
floatingActionButton: new Builder(builder: (BuildContext context) {
return new FloatingActionButton(
onPressed: () {
Scaffold.of(context)
.showSnackBar(new SnackBar(content: new Text("你点击了FloatingActionButton")));
},
child: const Icon(Icons.add),
//提示信息
tooltip: "请点击FloatingActionButton",
//前景色为白色
foregroundColor: Colors.white,
//背景色为蓝色
backgroundColor: Colors.blue,
//未点击阴影值
elevation: 7.0,
//点击阴影值
highlightElevation: 14.0,
mini: false,
shape: new CircleBorder(),
isExtended: false,
);
}),
//居中放置 位置可以设置成左中右
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);
}
}
1.2.3、TabBar水平选项卡及视图组件
class TabBarSameple extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new DefaultTabController(
length: items.length,
child: new Scaffold(
drawer: Drawer(
child: ListView(
children: <Widget>[
UserAccountsDrawerHeader(
accountName: new Text("李云龙"),
accountEmail: new Text("liyunlong.163.com"),
currentAccountPicture: new CircleAvatar(
backgroundImage: new AssetImage("images/look.jpg"),
),
decoration: new BoxDecoration(
//用一个BoxDecoration装饰器提供背景图片
image: new DecorationImage(
fit: BoxFit.fill,
// image: new NetworkImage('https://raw.githubusercontent.com/flutter/website/master/_includes/code/layout/lakes/images/lake.jpg')
//可以试试图片调取自本地。调用本地资源,需要到pubspec.yaml中配置文件路径
image: new ExactAssetImage('images/fengjing.jpg'),
),
),
onDetailsPressed: () {},
otherAccountsPictures: <Widget>[
new Container(
child: Image.asset("images/erweima.png"),
)
],
),
ListTile(
leading: new CircleAvatar(
child: Icon(Icons.color_lens),
),
title: Text("个性装扮"),
),
ListTile(
leading: new CircleAvatar(
child: Icon(Icons.photo),
),
title: Text("我的相册"),
),
ListTile(
leading: new CircleAvatar(
child: Icon(Icons.wifi),
),
title: Text("免流量特权"),
)
],
),
),
appBar: new AppBar(
title: const Text("TabBar选项卡示例"),
//标题居中
centerTitle: true,
//标题左侧按钮
leading: Icon(Icons.arrow_back),
//表示颜色是黄色,不透明度是0.5,最大值是1;以及大小是30,默认的大小是24
iconTheme:
IconThemeData(color: Colors.yellow, opacity: 0.5, size: 20),
//appbar背景色
backgroundColor: Color(0xffDE331F),
brightness: Brightness.light,
//控制状态栏的颜色,lignt 文字是灰色的,dark是白色的
//toolbar中显示的菜单
actions: <Widget>[
IconButton(
icon: Icon(Icons.search),
onPressed: () {},
tooltip: "搜索",
),
IconButton(
icon: Icon(Icons.add),
onPressed: () {},
tooltip: "添加",
),
//toolbar中显示的耳机菜单
PopupMenuButton(
itemBuilder: (BuildContext context) =>
<PopupMenuItem<String>>[
PopupMenuItem<String>(
child: Text("热度"),
value: "hot",
),
PopupMenuItem<String>(
child: Text("最新"),
value: "new",
),
],
onSelected: (String action) {
switch (action) {
case "hot":
print("hot");
break;
case "new":
print("new");
break;
}
},
//取消了pop二级菜单
onCanceled: () {
print("onCanceled");
},
),
],
bottom: new TabBar(
isScrollable: true,
tabs: items.map((ItemView item) {
return new Tab(
text: item.title,
icon: new Icon(item.icon),
);
}).toList()),
),
body: new TabBarView(
children: items.map((ItemView item) {
return new Padding(
padding: const EdgeInsets.all(16.0),
child: new SelcetedView(
item: item,
),
);
}).toList()),
)),
);
}
}
class ItemView {
const ItemView({this.title, this.icon});
final String title; //标题
final IconData icon;
}
const List<ItemView> items = const <ItemView>[
const ItemView(title: "自驾", icon: Icons.directions_car),
const ItemView(title: "自行车", icon: Icons.directions_bike),
const ItemView(title: "轮船", icon: Icons.directions_boat),
const ItemView(title: "公交车", icon: Icons.directions_bus),
const ItemView(title: "火车", icon: Icons.directions_railway),
const ItemView(title: "步行", icon: Icons.directions_walk),
];
//被选中的视图
class SelcetedView extends StatelessWidget {
const SelcetedView({Key key, this.item}) : super(key: key);
//视图数据
final ItemView item;
@override
Widget build(BuildContext context) {
final TextStyle textStyle = Theme.of(context).textTheme.display1;
return new Card(
color: Colors.white,
child: new Center(
child: new Column(
mainAxisSize: MainAxisSize.min, //垂直方向最小化处理
crossAxisAlignment: CrossAxisAlignment.center, //水平方向居中对齐
children: <Widget>[
new Icon(
item.icon,
size: 128.0,
color: textStyle.color,
),
new Text(
item.title,
style: textStyle,
)
],
),
),
);
}
}
②按钮和提示组件:包括按钮、菜单、对话框等
FloatingActionButton、FlatButton、PopupMenuButton、SimpleDialog、AlertDialog、SnackBar
2.1、FloatingActionButton对应一个圆形图标按钮,悬停在内容之上,以展示应用程序中的主要动作,所以非常醒目,类似于iOS系统中的小白点按钮,FloatingActionButton通常用于Scaffold.floatingActionButton字段
常见属性:
child:一般为Icon,不推荐使用文字
tooltip:按钮提示文字
onPressed:点击事件回调
shape:定义按钮的shape(ShapeBorder/CircleBorder(默认))
2.2FlatButton扁平按钮组件,点击时会有一个阴影效果
2.3PopupMenuButton弹出菜单组件,一般放在应用页面的右上角,表示有更多操作,菜单项使用PopupMenuItem组件
2.4SimpleDialog简单对话框组件
children:List 对话框子项,典型的应用是个列表
title:标题,通常是一个文本组件
通常对话框都是某个动作来触发渲染的,比如点击按钮,点击菜单,所以对话框一般要封装在一个方法里实现,另外这个过程需要加入async/await来处理
2.5AlertDialog,它要比SimpleDialog复杂一些,不仅仅有提示内容,还有一些操作属性,如确定取消等,内容部分可以使用SingleChildScrollView进行包裹
title:标题
content:内容部分,通常为对话框的提示内容
actions:对话框底部操作按钮可以使用List
2.6SnackBar(轻量提示组件)
Scaffold.of(context).showSnackBar(
SnackBar(
content:Text("显示内容"),
)
);
2.7其他组件
2.7.1TextField文本框组件
maxLength:最大长度
maxlines:最大行数
autocorrect:是否自动更正
autofocus:是否自动对焦
obscureText:是否是密码
texAlign:文本对齐方式
style:TextStyle输入文本样式
inputFormatters:允许的输入格式
onChanged:内容改变时的回调
onsubmitted内容提交时回调
enable:是否禁用
TextField(
//绑定controller
controller: controller,
//最大长度,设置此项会让textField右下角有一个输入数量的统计字符串
maxLength: 30,
//最大行数
maxLines: 1,
//是否自动更正
autocorrect: true,
//是否自动对焦
autofocus: true,
//是否是密码
obscureText: false,
//文本对齐方式
textAlign: TextAlign.center,
//输入文本的样式
style: TextStyle(fontSize: 26.0, color: Colors.green),
//文字内容改变时回调
onChanged: (text) {
print("文字内容改变时回调$text");
},
//内容提交时回调
onSubmitted: (text) {
print("内容提交时回调$text");
},
//是否禁用
enabled: true,
decoration: InputDecoration(
//添加装饰效果
fillColor: Colors.grey.shade200,
//添加灰色填充色
filled: true,
helperText: "用户名",
//左侧图标
prefixIcon: Icon(Icons.person),
//右侧文本提示
suffixText: "用户名"),
),
2.7.2Card卡片组件
card具有圆角和阴影,这让他看起来有立体感,可以使用SizeBox来限制它的大小
//卡片组件
SizedBox(
height: 200.0,
child: new Card(
child: new Column(
children: <Widget>[
new ListTile(
title: new Text(
"北京市丰台区外环西路",
style: new TextStyle(fontWeight: FontWeight.w300),
),
subtitle: new Text("北京平安快轿科技"),
leading: new Icon(
Icons.home,
color: Colors.lightBlue,
),
),
new Divider(
height: 1.0,
color: Color(0xffe0e0e0),
),
new ListTile(
title: new Text(
"北京市丰台区大红门",
style: new TextStyle(fontWeight: FontWeight.w300),
),
subtitle: new Text("百度牛逼有限公司"),
leading: new Icon(
Icons.home,
color: Colors.lightBlue,
),
),
new Divider(
height: 1.0,
color: Color(0xffe0e0e0),
),
],
),
),
),
第三部分:iOS风格组件
//导入
import 'package:flutter/cupertino.dart';
CupertinoActivityIndicator:loading风格指示器
CupertinoAlertDialog对话框组件
CupertinoButton:iOS风格的按钮
Cupertino导航组件集:
1:CupertinoTabScaffold选项卡组件
2:CupertinoTabBar选项卡按钮
2:CupertinoTabView选项卡视图
3:CupertinoPageScaffold页面的基本布局结构
3:CupertinoNavigationBar导航栏结构组件
第四部分:布局
4.1Container(容器布局)
4.2Center(居中布局)
通常情况下可直接添加子元素,不需要做额外属性设置
4.3Padding(填充布局)
用于处理容器与子元素之间的间距
4.4Align(对齐布局)
Align(
alignment:FractionalOffset.bottomRight,
child:Image.asset(""),
);
或者
Align(
alignment:FractionalOffset(1.0,0.0),
child:Image.asset(""),
);
4.5Row(水平布局)不可滚动
4.6Column(垂直布局)不可滚动
4.7FittedBox(缩放布局)
类似于Android中的ImageView,布局行为分为两种状况:
1:如果外部有约束的话,按照外部约束调整自身尺寸,然后缩放调整child,按照指定的条件进行布局
2:如果没有外部约束,则跟child尺寸 一致,指定的缩放及位置属性将不起作用
有fit(BoxFit枚举值)和alignment两个属性
4.8Stack/Alignment
Stack组件本身包含所有不定位的子组件,子组件根据alignment属性定位
4.9Stack/Positioned
子组件使用Positioned进行定位
4.10IndexedStack
继承自Stack,显示第index个child
4.11OverflowBox溢出父容器显示
允许子元素child超出父容器的范围显示
4.12SizedBox设置具体的尺寸
强制他的child有特定的宽度和高度
4.13ConstrainedBox(限定最大最小宽高布局)
如果child不为null,则将限制条件加载child上,否则,则会尽可能的缩小尺寸
4.14LimitedBox(限定最大宽高布局)
没有最小宽高限制
4.15AspectRatio(调整宽高比)
最终显示不一定按照这个宽高比
**aspextRatio:宽高比:**不能为空,其值必须大于零
4.16FractionallySizedBox(百分比布局)
三个属性:
alignment:对齐方式,不能为空
widthFactor:宽度因子
heightFactor:高度因子
设置了宽高因子,具体的宽高根据现有宽高*因子,当宽高因子大于1的时候,可能会超出父组件的范围
没有设置宽高因子,则填满可用区域
4.17网格布局
ListView/GridView/Table
4.18其他布局
Transform矩阵变换
Baseline基准线布局
Offstage控制是否显示组件
Wrap按照宽高自动换行布局:类似于流式布局