Flutter Widget采用现代响应式框架构建,中心思想是用widget构建你的UI。Widget描述了他们的视图在给定其当前配置和状态时看起来像什么。当widget的状态发生变化时,widget会重新构建UI,Flutter会对比前后变化的不同,以确定底层渲染树从一个状态转换到下一个状态所需的最小更改。
Flutter有一套丰富的基础widget。
下面是一个简单的代码示例
void main() => runApp(new MaterialApp(title: 'My App', home: new MyScaffold()));
class MyAppBar extends StatelessWidget {
final Widget title;
@override
Widget build(BuildContext context) {
return new Container(
height: 56.0,
padding: const EdgeInsets.symmetric(horizontal: 8.0),
decoration: new BoxDecoration(color: Colors.blue[500]),
child: new Row(
children: [
new IconButton(
icon: new Icon(Icons.menu),
tooltip: "Navigation menu",
onPressed: null),
new Expanded(child: title),
new IconButton(
icon: new Icon(Icons.search), tooltip: "Search", onPressed: null)
],
),
);
}
MyAppBar({this.title});
}
class MyScaffold extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Material(
child: new Column(
children: [
new MyAppBar(
title: new Text(
"Expanded Title",
style: Theme.of(context).primaryTextTheme.title,
)),
new Expanded(
child: new Center(
child: new Text("Hello Flutter"),
))
],
),
);
}
}
Flutter提供了许多widgets,可以构建遵循Material Design的应用程序。Material应用程序已MaterialApp widget开始,该weiget在应用程序的根部创建了一些有用的widget,包括一个Navigator,它管理由字符串便是的Widget栈,Navigator可以让应用程序在页面之间平滑的过渡。
以下为简单floatingBar的代码示例
class TutorialHome extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
leading: new IconButton(
icon: new Icon(Icons.menu),
tooltip: "Navigation menu",
onPressed: null),
title: new Text("Example title"),
actions: [
new IconButton(
icon: new Icon(Icons.search), tooltip: "Search", onPressed: null)
],
),
body: new Center(
child: new Text("Hello world"),
),
floatingActionButton: new FloatingActionButton(
tooltip: "Add", child: new Icon(Icons.add), onPressed: null),
);
}
}
class MyButton extends StatelessWidget{
@override
Widget build(BuildContext context) {
return new GestureDetector(
onTap: (){
print("button was tapped");
},
child: new Container(
height: 36.0,
padding: const EdgeInsets.all(8.0),
decoration: new BoxDecoration(
borderRadius: new BorderRadius.circular(5.0),
color: Colors.lightGreen[500],
),
child: new Center(
child: new Text("Engage"),
),
),
);
}
}
当用户点击Container时,GestureDetector会调用它的onTap回调,同样也可以在GestureDetector中监测各种手势
上面使用的widget是无状态的widget,无状态widget从他们的父widget接收参数,他们被存储在final型的成员变量中,当一个widget被要求构建时,它使用这些存储的值作为参数来构建widget
为了构建更复杂的体验,Flutter会使用StatefulWidget来满足这种需求。StatefulWidget是特殊的widget,它知道如何生成State对象,然后用它来保持状态。
class Counter extends StatefulWidget {
@override
State createState() {
return new CounterState();
}
}
class CounterState extends State<Counter> {
int _counter = 0;
void increment() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return new Row(
children: [
new RaisedButton(
onPressed: increment,
child: new Text("Increment"),
),
new Text("Count:$_counter"),
],
);
}
}
StatefulWidget和State是单独的对象,在Flutter中,这两种类型的对象有不同的生命周期:Widget是临时对象,用于构建当前状态下的应用程序,而State独享在多次调用build之间保持不变,允许他们记住信息
在Flutter中,事件流是向上传递的,而状态流是向下传递的,子widget到父widget是通过事件传递的,而父到子是通过状态。重定向这一流程的共同父元素是State。
下面将逻辑分别封装在各个widget中,保持父项的简单性:
class CounterDisplay extends StatelessWidget {
CounterDisplay({this.count});
final int count;
@override
Widget build(BuildContext context) {
return new Text("Count:$count");
}
}
class CounterIncrementor extends StatelessWidget {
CounterIncrementor({this.onPressed});
final VoidCallback onPressed;
@override
Widget build(BuildContext context) {
return new RaisedButton(
onPressed: onPressed,
child: new Text("Increment"),
);
}
}
class Counter extends StatefulWidget {
@override
State createState() {
return new CounterState();
}
}
class CounterState extends State<Counter> {
int _counter = 0;
void increment() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return new Row(
children: [
new CounterIncrementor(onPressed: increment),
new CounterDisplay(count: _counter)
],
);
}
}
在StatefulWidget调用createState之后,框架将新的状态插入树种,然后调用状态对象的initState。子类化State可以重写initState,以完成仅需要一次执行的工作。当然在initState的实现中需要调用super.initState
当一个状态对象不再需要时,框架调用状态对象的dispose。也可以通过覆盖dispose方法来执行清理工作。