Flutter有两个常用的状态类:
站在用户的角度思考问题,与客户深入沟通,找到陵城网站设计与陵城网站推广的解决方案,凭借多年的经验,让设计与互联网技术结合,创造个性化、用户体验好的作品,建站类型包括:成都做网站、网站建设、企业官网、英文网站、手机端网站、网站推广、域名注册、虚拟主机、企业邮箱。业务覆盖陵城地区。
标记为dirty,执行的markNeedsBuild,定义在Element类中:
当前Element节点被标记为dirty,同时调用owner的scheduleBuildFor方法:
将element元素添加到全局的“脏”链表里。
BuildOwner用来管理哪些需要更新的Widget。这个owner最开始被初始化的地方在WidgetsBinding的initInstances方法中,随后初始化了onBuildScheduled方法,对应执行的是_handleBuildScheduled,定义在WidgetsBinding类中:
ensureVisualUpdate 方法定义在SchedulerBinding类中:
在提交下一帧绘制的时候会调用到scheduleFrame方法,提交给引擎绘制,看看scheduleFrame方法,也定义在SchedulerBinding类中:
提交给引擎绘制之后,会收到onDrawFrame的回调,最终执行到_handleDrawFrame方法中,对应的是handleDrawFrame方法,定义在SchedulerBinding类中:
在RendererBinding的initInstances方法中添加了一个回调到这个List中,对应的是RenderBinding的drawFrame方法,对应的节点进行绘制渲染操作。
WidgetsBinding中的drawFrame方法:
看看这里的buildScope方法,定义在BuildOwner方法中。在上面 scheduleBuildFor 方法介绍中有提到:"scheduleBuildFor 是把一个 element 添加到 _dirtyElements 链表,以便当[WidgetsBinding.drawFrame]中调用 buildScope 的时候能够重构 element。onBuildScheduled()是一个 BuildOwner 的回调"。在 drawFrame 中调用 buildOwner.buildScope(renderViewElement)更新 elements。
_dirtyElements列表在遍历的过程中执行rebuild方法,此时将所有标记为dirty的Element节点依次执行rebuild,preformRebuild,build,updateChild,update方法,执行界面更新。完成build,update操作完成之后,后续会将需要绘制的RenderObject添加到需要layout的列表中,等待绘制渲染。所有绘制完成之后将_dirtyElments列表清空,_inDirtyList标记位置为false。
提交给引擎绘制渲染
看看super.drawFrame(),这里就执行到了RendererBinding类中,定义如下:
这里就是将最终需要绘制渲染的画面提交给引擎的地方了,绘制完成之后就在界面显示更新后的视图了。
Flutter中Widget分为StatefulWidget和StatelessWidget,分别为动态视图和静态视图,视图的更新需要调用StatefulWidget的setState方法,这会遍历调用子Widget的build方法。当一个主页面比较复杂时,会包含多个widget,如果直接调用setState,会遍历所有子Widget的build,这是非常不必要的性能开销,有没有单独刷新指定Widget的方式呢?这个时候就要用到GlobalKey了。
一个StatefulWidget包含一个Button,一个Text,通过点击Button调用主Widget的setState方法,刷新Text,示例如下:
同样一个StatefulWidget包含一个多个Text和Button,点击Button我们只需要刷新指定的Text,通过GlobalKey的方式,实现如下:
主Widget,包含一个需要更新的TextWidget和一个不需要更新的Text
需要单独更新的Widget
传递事件的Button
这样点击Button就只会更新指定的TextWidget了,效果如下:
这只是一个简单的例子,在实际开发中为了页面刷新的高效率,模块化封装非常重要。很多情况下都只需要局部刷新,而不是重构整个视图。所以Globalkey的运用在项目中需要熟练掌握
我是在StatefulWidget里面设置了一个全局的List,然后动态改变List里面的内容,然后使用setState刷新,结果发现没有用,点击一下虽然会多出一个新的Item,但是还是原来那个,就是List长度、内容不同,Widget显示的是同一个Widget。
比如:九宫格添加图片,第一个是添加图片,点击添加图片把图片放到List里面,然后setState刷新,结果发现页面没变化,触碰添加图片Item,就会多出一个添加图片Item。
根据Flutter基于不可变数据的原理,我们直接把List换一个引用,创建一个新的List。
这种方法最常见,但是有些地方引用的话,刷新的成本比较大,刷新的是整个页面,数据太多加载太慢的话,会有闪烁的现象
这种方法类似于iOS中的set方法,通过设置某个属性的时候,去刷新某个控件。在flutter中这种刷新方式,是对上面setState(){}方法的改进,根本的方法还是setState(){},只不过是通过方法去刷新某个控件。如下:
首先在pubspec.yaml中添加provider依赖
下面通过provider来实现一个发送验证码的案例。
创建一个TimerModel文件
页面布局如下: