Flutter Counter
如何写一个 Flutter 应用
我们从一个计数器讲起, 首先建立 Counter 类
class Counter extends StatelessWidget {
Counter(): super();
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
title: 'Flutter Counter',
theme: ThemeData(primarySwatch: Colors.blue),
home: CounterHomePage(title: 'Flutter Counter Home Page'),
);
}
}
在内部定义了构造方法,并且重构了 build 方法 其中 build 方法返回了一个 MaterialApp ,这就是 Flutter 提供的根组件,接下来只需提供一个 Widget ,将其赋值给 home 作为主页程序即可 再来看看赋值 home 的组件 CounterHomePage 是怎么写的
class CounterHomePage extends StatefulWidget {
CounterHomePage({this.title = 'Hello World'}): super();
String title;
@override
CounterHomePageState createState() => CounterHomePageState();
}
这个类继承自 StatefulWidget ,与 Counter 类继承的 StatelessWidget 成对比, Counter 是无状态的组件, CounterHomePage 是有状态的组件 其中重写了 StatefulWidget 的 createState 方法,返回值是用来管理其状态的 CounterHomePageState
class CounterHomePageState extends State<CounterHomePage> {
int count = 0;
void incrementCount() {
setState(() {
count += 1;
});
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(title: Text(widget.title),),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('You have pushed the button this many times:'),
Text(count.toString(), style: Theme
.of(context)
.textTheme
.headline4),
TextButton(
child: Text('Open new route'),
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context){
return NewRoute();
}));
},)
]
),
),
floatingActionButton: FloatingActionButton(
onPressed: incrementCount,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
其中该类继承自泛型类 State<CounterHomePage> ,与 CounterHomePage 相关联 需要改变状态的时候,调用 setState 即可,该函数接收一个闭包。 而后, Flutter 框架检测到状态改变,销毁原来 build 的 CouterHomePageState ,而是重新调用 build 来代替 在程序中,改变状态通过 TextButton 的 OnPressed 回调来触发
还有一个程序的入口,主函数没有写
void main() => runApp(Counter());
至此,我们的第一个计数器应用就搭建完毕了
什么是 Scaffold 组件
在上面的 CounterHomePageState 中,还有个 Scaffold 组件没有讲,这是 Flutter 为我们提供的主页, 官网的描述:Material Design布局结构的基本实现, 类提供了用于显示drawer、snackbar和底部sheet的API。 可以编辑他的 appBar , body 属性,其中 body 作为主页的主体,随便放个组件进去就行了
如何布局多个组件
Scaffold 的 body 只能传递一个组件,想把一堆东西塞进去,可以使用 Flutter 提供的 布局组件 该类组件都有一个 children 属性,表示一个 Widget 数组 在上面的例子中, Column 就是一个布局组件,按竖直方向布局组件,并赋值 mainAxisalignment 为 center 表示主轴方向垂直对齐
等等, Column 上面还有个 Center 组件是怎么回事? 他为什么用 child ,而不用 children ? Center 是一个容器组件,只有一个子元素,用 child 表示
布局类Widget是按照一定的排列方式来对其子Widget进行排列; 而容器类Widget一般只是包装其子Widget,对其添加一些修饰(补白或背景色等)、变换(旋转或剪裁等)、或限制(大小等)。 注意,Flutter官方并没有对Widget进行官方分类,我们对其分类主要是为了方便讨论和对Widget功能区分的记忆
除了 Center 外,其他容器类还有
- 填充(Padding)
- 尺寸限制类容器(ConstrainedBox等)
- 装饰容器(DecoratedBox)
- 变换(Transform)
- Container容器
- Scaffold、TabBar、底部导航
- 剪裁(Clip)
如何修饰样式
像 css 样式一样, flutter 中样式也可以继承,如果要更改,用 Theme 组件包装一下就可以了 其中 Theme 组件
Theme({Key? key, required ThemeData data, required Widget child})
最重要的是 ThemeData 这个结构, child 表示需要修饰的组件
对比 html 语法
对比 html 的标签语法,比如
<div>
</div>
<style>
div {
padding: 12px;
}
</style>
可以用 Padding 组件写为
Padding(
padding: EdgeInsets.all(12)
);
感觉是把一些属性单独提取出来,做成一个组件,如果需要修饰大量样式,应该用 Theme 组件