Flutter Counter
Table of Contents
如何写一个 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 组件