|
目录
简介
Widget
StatelessWidget 案例:自定义Button
StatefulWidget 案例:更新UI
效果图:
总结
简介
Flutter是谷歌开发的跨平台UI工具包。通过一套代码库,我们能够构建出能运行在Android,IOS上的APP,本文总结介绍Flutter中的Widget,期待能达到抛砖引玉的作用。
Flutter提出了一切皆Widget的设计思想,如同汽车领域,使用零部件组装汽车一样,Flutter利用Widget来“组装”应用。

vs???
?
?上面Widgets组合起来的是一个树形结构:

Widget分为两类:StatelessWidget和StatefulWidget,下面用两个案例来理解其区别。
需求:把系统FloatActionButton替换成自定义的Button,这里采用渐进的演示,逐步用5个子Widget来组合一个带图片、文字且圆角的Button。
1.显示一个文本的按钮
@override
Widget build(BuildContext context) { //?
return Text("新增活动"); //button上面的文字,一旦设置后就不可变
}
2.接着,用RawMaterialButton包裹文本,让它可以添加点击事件
@override
Widget build(BuildContext context) {
return RawMaterialButton(
// fillColor: Colors.deepOrange,
// splashColor: Colors.orange,
onPressed: onPressed,
child: Text("新增活动")); //button上面的文字,一旦设置后就不可变
}
3.然后,给Button设置圆角样式
@override
Widget build(BuildContext context) {
return RawMaterialButton(
fillColor: Colors.deepOrange,
splashColor: Colors.orange,
child: Text("新增活动", style: TextStyle(color: Colors.white)),
shape: StadiumBorder(),
onPressed: onPressed,
);
}
4.给Button添加左边的图片
@override
Widget build(BuildContext context) {
return RawMaterialButton(
padding: EdgeInsets.only(left: 20, right: 20),
fillColor: Colors.deepOrange,
splashColor: Colors.orange,
child: Row(
mainAxisSize: MainAxisSize.min, //row的宽度最小化,包括子控件即可。
children: [
Icon(Icons.add, color: Colors.yellow),
Text(
"新增活动",
style: TextStyle(color: Colors.white),
)
],
),
shape: StadiumBorder(),
onPressed: onPressed,
);
}
5.调整文本与图片的间距
@override
Widget build(BuildContext context) {
return RawMaterialButton(
fillColor: Colors.deepOrange,
splashColor: Colors.orange,
padding: EdgeInsets.only(left: 20, right: 20),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.add, color: Colors.yellow),
SizedBox(
width: 10,
),
Text(
"新增活动",
style: TextStyle(color: Colors.white),
)
],
),
shape: StadiumBorder(),
onPressed: onPressed,
);
}
按照上面的步骤,给button配置完属性后,button的状态是不再改变的,那么这样的Widget可以称为StatelessWidget。
最终效果:

?完整代码:
import 'package:flutter/material.dart';
class NewActivityButton extends StatelessWidget {
final GestureTapCallback onPressed; //点击事件的回调,一旦设置后就不可变
NewActivityButton({required this.onPressed});
///sizeBox增加图片和文字的间距
///RawMaterialButton -> Row -> Icon & SizeBox & Text
@override
Widget build(BuildContext context) {
return RawMaterialButton(
fillColor: Colors.deepOrange,
splashColor: Colors.orange,
padding: EdgeInsets.only(left: 20, right: 20),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.add, color: Colors.yellow),
SizedBox(
width: 10,
),
Text(
"新增活动",
style: TextStyle(color: Colors.white),
)
],
),
shape: StadiumBorder(),
onPressed: onPressed,
);
}
}
StatefulWidget 案例:更新UI
如何更新Widget需要满足两个条件。首先这个Widget是StatefulWidget类型,其次我们还需编写一个State类,由它来维护widget的生命周期。
需求:在首页,点击NewActivityButton后,需要向ListView的数据中新增一个Item,并刷新UI。
1. 定义首页Widget
/// 首页
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
/// 创建State, 监听Widget的生命周期,同时负责重新构建Widget
@override
_MyHomePageState createState() => _MyHomePageState();
}
?///定义State
class _MyHomePageState extends State<MyHomePage> {
/// setStated执行后, build方法将被系统调用。
/// 定义根widget以及挂载它下面的子树
@override
Widget build(BuildContext context) {
print("build~~~~~~~~~~~~~");
return Scaffold(
...
child: ListView.builder(
itemCount: _items.length,
itemBuilder: (BuildContext context, int index) {
print(index);
return ListTile(
leading: Icon(Icons.ondemand_video),
// leading: Image.network("https://img2.baidu.com/it/u=1106670559,3141264106&fm=26&fmt=auto"),
title: Text(_items[index].name),
);
},
),
),
....
);
}
}
?
2.在State类中,定义私有数据items,随后绑定到listview
class _MyHomePageState extends State<MyHomePage> {
///定义listview的数据
final _items =
List<ActivityEntity>.generate(5, (i) => ActivityEntity("活动 $i"));
...
}
3.定义点击事件,在setState()内更新数据,这个数据将驱动框架内部刷新UI.
///这里发布活动, setState() 会触发widget刷新。
///
void _addActivity() {
//setState是系统函数, 调用此方法,系统会刷新UI, 通知系统,重建build()=>widget,
//如果我们改变_items的内容,而没有调用setState方法,build方法则不会被系统调用,UI也不会发生任何改变。
setState(() {
ActivityEntity entity =
ActivityEntity("活动 ${DateTime.now().millisecondsSinceEpoch}");
_items.add(entity);//数据驱动页面刷新
});
}
4.给button绑定这个更新数据的方法
floatingActionButton: NewActivityButton(
onPressed: _addActivity,
)
注意:这里setState()执行时,系统框架会检测State类中数据发生改变,然后重新调用build(),重新实例化一个新widget的对象。所以widget是比较轻量的,如果有数据操作需要在State类中进行。
效果图:

总结
1. Flutter由Widgets组合而成。除了上面提到的Widget,官方还提供了很多基础控件,包括对动画,Canvas的支持。
2. StatefulWidget是用来定义一个可变的控件,内部细节还有很多值得深入学习的地方。
?Demo代码在:https://github.com/zengqiang24/FlutterWidget
文中若有错误的地方,欢迎指正。谢谢!
|