前言一:接下来一段时间我会陆续更新一些列Flutter文字教程html
更新进度: 每周至少两篇;前端
更新地点: 首发于公众号,次日更新于掘金、思否、开发者头条等地方;vue
更多交流: 能够添加个人微信 372623326,关注个人微博:coderwhy算法
但愿你们能够 帮忙转发,点击在看,给我更多的创做动力。编程
在开发中,某些Widget状况下咱们展现的数据并非一层不变的:api
好比Flutter默认程序中的计数器案例,点击了+号按钮后,显示的数字须要+1;浏览器
好比在开发中,咱们会进行下拉刷新、上拉加载更多,这时数据也会发生变化;微信
而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类的相关方法:
一、执行State类的构造方法(Constructor)来建立State对象;
二、执行initState,咱们一般会在这个方法中执行一些数据初始化的操做,或者也可能会发送网络请求;
三、执行didChangeDependencies方法,这个方法在两种状况下会调用
四、Flutter执行build方法,来看一下咱们当前的Widget须要渲染哪些Widget;
五、当前的Widget再也不使用时,会调用dispose进行销毁;
六、手动调用setState方法,会根据最新的状态(数据)来从新调用build方法,构建对应的Widgets;
七、执行didUpdateWidget方法是在当父Widget触发重建(rebuild)时,系统会调用didUpdateWidget方法;
咱们来经过代码进行演示:
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、数据结构与算法等等,也会更新一些本身的学习心得等,欢迎你们关注