前言一:接下来一段时间我会陆续更新一些列Flutter文字教程更新进度: 每周至少两篇;html
更新地点: 首发于公众号,次日更新于掘金、思否、开发者头条等地方;前端
更多交流: 能够添加个人微信 372623326,关注个人微博:coderwhyvue
但愿你们能够 帮忙转发,点击在看,给我更多的创做动力。算法
在开发中,某些Widget状况下咱们展现的数据并非一层不变的:好比Flutter默认程序中的计数器案例,点击了+号按钮后,显示的数字须要+1;编程
好比在开发中,咱们会进行下拉刷新、上拉加载更多,这时数据也会发生变化;api
而StatelessWidget一般用来展现哪些数据固定不变的,若是数据会发生改变,咱们使用StatefulWidget;浏览器
若是你有阅读过默认咱们建立Flutter的示例程序,那么你会发现它建立的是一个StatefulWidget。微信
为何选择StatefulWidget呢?网络
变量
来记录当前的状态,再把这个变量显示到某个Text Widget上;变量
发生改变时,咱们对应的Text上显示的内容也要发生改变;可是有一个问题,我以前说过定义到Widget中的数据都是不可变的,必须定义为final,为何呢?数据结构
成员变量
必须是final
的;Flutter如何作到咱们在开发中定义到Widget中的数据必定是final的呢?
咱们来看一下Widget的源码:
@immutable abstract class Widget extends DiagnosticableTree { // ...省略代码 }
这里有一个很关键的东西@immutable
注解
,这设计到Dart的元编程,咱们这里不展开讲;实际上官方有对@immutable进行说明:
结论: 定义到Widget中的数据必定是不可变的,须要使用final来修饰
既然Widget是不可变,那么StatefulWidget如何来存储可变的状态呢?
Flutter将StatefulWidget设计成了两个类:
建立一个StatefulWidget,咱们一般会按照以下格式来作:
State的实例
,而且它调用build方法去获取StatefulWidget但愿构建的Widget;class MyStatefulWidget extends StatefulWidget { @override State<StatefulWidget> createState() { // 将建立的State返回 return MyState(); } } class MyState extends State<MyStatefulWidget> { @override Widget build(BuildContext context) { return <构建本身的Widget>; } }
思考:为何Flutter要这样设计呢?
这是由于在Flutter中,只要数据改变了Widget就须要从新构建(rebuild)
咱们经过一个案例来练习一下StatefulWidget,仍是以前的计数器案例,可是咱们按照本身的方式进行一些改进。
案例效果以及布局以下:
onPress属性
是传入一个回调函数
,当按钮点击时被回调;下面咱们来看看代码实现:
class MyCounterWidget extends StatefulWidget { @override State<StatefulWidget> createState() { // 将建立的State返回 return MyCounterState(); } } class MyCounterState extends State<MyCounterWidget> { int counter = 0; @override Widget build(BuildContext context) { return Center( child: Text("当前计数:$counter", style: TextStyle(fontSize: 30),), ); } }
class MyCounterState extends State<MyCounterWidget> { int counter = 0; @override Widget build(BuildContext context) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ RaisedButton( color: Colors.redAccent, child: Text("+1", style: TextStyle(fontSize: 18, color: Colors.white),), onPressed: () { }, ), RaisedButton( color: Colors.orangeAccent, child: Text("-1", style: TextStyle(fontSize: 18, color: Colors.white),), onPressed: () { }, ) ], ), Text("当前计数:$counter", style: TextStyle(fontSize: 30),) ], ), ); } }
咱们如今要监听状态的改变,当状态改变时要修改counter变量
:
如何可让Flutter知道咱们的状态发生改变了,从新构建咱们的Widget呢?
onPressed: () { setState(() { counter++; }); },
这样就能够实现想要的效果了:
什么是生命周期呢?
Flutter小部件的生命周期:
在这个版本中,我讲解那些经常使用的方法和回调,下一个版本中我解释一些比较复杂的方法和回调
那么StatefulWidget有哪些生命周期的回调呢?它们分别在什么状况下执行呢?
咱们知道StatefulWidget自己由两个类组成的:StatefulWidget
和State
,咱们分开进行分析
首先,执行StatefulWidget中相关的方法:
其次,调用createState建立State对象时,执行State类的相关方法:
二、执行initState,咱们一般会在这个方法中执行一些数据初始化的操做,或者也可能会发送网络请求;
咱们来经过代码进行演示:
import 'package:flutter/material.dart'; main(List<String> args) { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: Text("HelloWorld"), ), body: HomeBody(), ), ); } } class HomeBody extends StatelessWidget { @override Widget build(BuildContext context) { print("HomeBody build"); return MyCounterWidget(); } } class MyCounterWidget extends StatefulWidget { MyCounterWidget() { print("执行了MyCounterWidget的构造方法"); } @override State<StatefulWidget> createState() { print("执行了MyCounterWidget的createState方法"); // 将建立的State返回 return MyCounterState(); } } class MyCounterState extends State<MyCounterWidget> { int counter = 0; MyCounterState() { print("执行MyCounterState的构造方法"); } @override void initState() { super.initState(); print("执行MyCounterState的init方法"); } @override void didChangeDependencies() { // TODO: implement didChangeDependencies super.didChangeDependencies(); print("执行MyCounterState的didChangeDependencies方法"); } @override Widget build(BuildContext context) { print("执行执行MyCounterState的build方法"); return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ RaisedButton( color: Colors.redAccent, child: Text("+1", style: TextStyle(fontSize: 18, color: Colors.white),), onPressed: () { setState(() { counter++; }); }, ), RaisedButton( color: Colors.orangeAccent, child: Text("-1", style: TextStyle(fontSize: 18, color: Colors.white),), onPressed: () { setState(() { counter--; }); }, ) ], ), Text("当前计数:$counter", style: TextStyle(fontSize: 30),) ], ), ); } @override void didUpdateWidget(MyCounterWidget oldWidget) { super.didUpdateWidget(oldWidget); print("执行MyCounterState的didUpdateWidget方法"); } @override void dispose() { super.dispose(); print("执行MyCounterState的dispose方法"); } }
打印结果以下:
flutter: HomeBody build flutter: 执行了MyCounterWidget的构造方法 flutter: 执行了MyCounterWidget的createState方法 flutter: 执行MyCounterState的构造方法 flutter: 执行MyCounterState的init方法 flutter: 执行MyCounterState的didChangeDependencies方法 flutter: 执行执行MyCounterState的build方法 // 注意:Flutter会build全部的组件两次(查了GitHub、Stack Overflow,目前没查到缘由) flutter: HomeBody build flutter: 执行了MyCounterWidget的构造方法 flutter: 执行MyCounterState的didUpdateWidget方法 flutter: 执行执行MyCounterState的build方法
当咱们改变状态,手动执行setState方法后会打印以下结果:
flutter: 执行执行MyCounterState的build方法
咱们来学习几个前面生命周期图中提到的属性,可是没有详细讲解的
一、mounted是State内部设置的一个属性,事实上咱们不了解它也能够,可是若是你想深刻了解它,会对State的机制理解更加清晰;
二、dirty state的含义是脏的State
三、clean state的含义是干净的State
这个章节又讲解一些理论的东西,可能并不会直接讲授Flutter的知识,可是会对你之后写任何的代码,都具有一些简单的知道思想;
编程范式对于初学编程的人来讲是一个虚无缥缈的东西,可是倒是咱们平常开发中都在默认遵循的一些模式和方法;
好比咱们最为熟悉的 面向对象编程
就是一种编程范式,与之对应或者结合开发的包括:面向过程编程、函数式编程、面向协议编程;
另外还有两个对应的编程范式:命令式编程
和 声明式编程
上面的描述仍是太笼统了,咱们来看一些具体点的例子;
下面的代码没有写过前端的能够简单看一下
下面的代码是在前端开发中我写的两个demo,做用都是点击按钮后修改h2标签的内容:
从2009年开始(数据来自维基百科),声明式编程就开始流行起来,而且目前在Vue、React、包括iOS中的SwiftUI中以及Flutter目前都采用了声明式编程。
如今咱们来开发一个需求:显示一个Hello World,以后又修改为了Hello Flutter
若是是传统的命令式编程,咱们开发Flutter的模式极可能是这样的:(注意是想象中的伪代码)
final text = new Text(); var title = "Hello World"; text.setContent(title); // 修改数据 title = "Hello Flutter"; text.setContent(title);
若是是声明式编程,咱们一般会维护一套数据集:
var title = "Hello World"; Text(title); // 告诉Text内部显示的是title // 数据改变 title = "Hello Flutter"; setState(() => null); // 通知从新build Widget便可
上面的代码过于简单,可能不能体现出Flutter声明式编程的优点所在,可是在之后的开发中,咱们都是按照这种模式在进行开始,咱们一块儿来慢慢体会;
备注:全部内容首发于公众号,以后除了Flutter也会更新其余技术文章,TypeScript、React、Node、uniapp、mpvue、数据结构与算法等等,也会更新一些本身的学习心得等,欢迎你们关注