可滚动组件中缓存指定子项的通用方案
在介绍 ListView 时,有一个addAutomaticKeepAlives
属性我们并没有介绍,如果addAutomaticKeepAlives
为 true
,则 ListView 会为每一个列表项添加一个 AutomaticKeepAlive 父组件。
虽然 PageView 的默认构造函数和 PageView.builder 构造函数中没有该参数,但它们最终都会生成一个 SliverChildDelegate 来负责列表项的按需加载。
而在 SliverChildDelegate 中每当列表项构建完成后,SliverChildDelegate 都会为其添加一个 AutomaticKeepAlive 父组件。下面我们就先介绍一下 AutomaticKeepAlive 组件。
1. AutomaticKeepAlive
AutomaticKeepAlive 的组件的主要作用是将列表项的根 RenderObject 的 keepAlive 按需自动标记 为 true 或 false。为了方便叙述,我们可以认为根 RenderObject 对应的组件就是列表项的根 Widget,代表整个列表项组件,同时我们将列表组件的 Viewport区域 + cacheExtent(预渲染区域)称为加载区域 :
当 keepAlive 标记为 false 时,如果列表项滑出加载区域时,列表组件将会被销毁。
当 keepAlive 标记为 true 时,当列表项滑出加载区域后,Viewport 会将列表组件缓存起来;当列表项进入加载区域时,Viewport 从先从缓存中查找是否已经缓存,如果有则直接复用,如果没有则重新创建列表项。
那么 AutomaticKeepAlive 什么时候会将列表项的 keepAlive 标记为 true 或 false 呢?答案是开发者说了算!Flutter 中实现了一套类似 C/S 的机制,AutomaticKeepAlive 就类似一个 Server,它的子组件可以是 Client,这样子组件想改变是否需要缓存的状态时就向 AutomaticKeepAlive 发一个通知消息(KeepAliveNotification),AutomaticKeepAlive 收到消息后会去更改 keepAlive 的状态,如果有必要同时做一些资源清理的工作(比如 keepAlive 从 true 变为 false 时,要释放缓存)。
我们基于上一节 PageView 示例,实现页面缓存,根据上面的描述实现思路就很简单了:让Page 页变成一个 AutomaticKeepAlive Client 即可。为了便于开发者实现,Flutter 提供了一个 AutomaticKeepAliveClientMixin ,我们只需要让 PageState 混入这个 mixin,且同时添加一些必要操作即可:
class _MSPageItemState extends State<MSPageItem>
with AutomaticKeepAliveClientMixin {
@override
Widget build(BuildContext context) {
// super.build(context);
print("flutter build ${widget.text}");
return Center(child: Text(widget.text!, textScaleFactor: 5.0));
}
@override
bool get wantKeepAlive => true;
}
代码很简单,我们只需要提供一个 wantKeepAlive,它会表示 AutomaticKeepAlive 是否需要缓存当前列表项;
现在我们重新运行一下示例,发现每个 Page 页只会 build 一次,缓存成功了。
2. KeepAliveWrapper
虽然我们可以通过 AutomaticKeepAliveClientMixin 快速的实现页面缓存功能,但是通过混入的方式实现不是很优雅,因为必须更改 Page 的代码,有侵入性,这就导致不是很灵活,比如一个组件能同时在列表中和列表外使用,为了在列表中缓存它,则我们必须实现两份。
wendux 大神提供了一个KeepAliveWrapper组件,如果哪个列表项需要缓存,只需要使用 KeepAliveWrapper 包裹一下它即可
@override
Widget build(BuildContext context) {
var children = <Widget>[];
for (int i = 0; i < 6; ++i) {
//只需要用 KeepAliveWrapper 包装一下即可
children.add(KeepAliveWrapper(child:Page( text: '$i'));
}
return PageView(children: children);
}
下面是 KeepAliveWrapper 的实现源码:
class KeepAliveWrapper extends StatefulWidget {
const KeepAliveWrapper(
{Key? key, @required this.child, this.keepAlive = true})
: super(key: key);
final Widget? child;
final bool keepAlive;
@override
State<KeepAliveWrapper> createState() => _KeepAliveWrapperState();
}
class _KeepAliveWrapperState extends State<KeepAliveWrapper>
with AutomaticKeepAliveClientMixin {
@override
Widget build(BuildContext context) {
return widget.child!;
}
@override
bool get wantKeepAlive => widget.keepAlive;
@override
void didUpdateWidget(covariant KeepAliveWrapper oldWidget) {
if (oldWidget.keepAlive != widget.keepAlive) {
// keepAlive 状态需要更新,实现在 AutomaticKeepAliveClientMixin 中
updateKeepAlive();
}
super.didUpdateWidget(oldWidget);
}
}
测试下
class KeepAliveDemo extends StatelessWidget {
const KeepAliveDemo({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return PageView.builder(
itemCount: 5,
itemBuilder: (BuildContext ctx, int index) {
return KeepAliveWrapper(
child: PageItem(text: "$index"),
keepAlive: true,
);
},
);
}
}
class PageItem extends StatelessWidget {
PageItem({this.text});
final String? text;
@override
Widget build(BuildContext context) {
print("flutter build ${text}");
return Center(child: Text(text!, textScaleFactor: 5.0));
}
}
运行发现,keepAlive为true时每个Item都缓存了,为false时,每个Item都会重新创建,OK。
本文转自 https://www.jianshu.com/p/47acfb0d74f6,如有侵权,请联系删除。
有需要更多完整学习资料的,可以扫描下方二维码领取资料!
Flutter技术解析与实战,全家桶学习资料(含Flutter进阶学习笔记、入门与实战和完整开发实战详解)
Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面。 Flutter可以与现有的代码一起工作。在全世界,Flutter正在被越来越多的开发者和组织使用,并且Flutter是完全免费、开源的。
在这里为了方便大家系统的学习Flutter,这里特意联合了阿里P7架构师和谷歌技术团队共同整理了一份Flutter全家桶学习资料。
内容概要:Flutter技术解析与实战、Flutter进阶学习笔记、Flutter入门与实战和Flutter完整开发实战详解。
内容特点:条理清晰,含图像化表示更加易懂。
由于文章内容比较多,篇幅有限,资料已经被整理成了PDF文档,有需要 Flutter技术解析与实战 完整文档的可扫描下方卡片免费获取!
《Flutter技术解析与实战》
目录
第一章 混合工程
● Flutter工程体系
● 混合工程改造实战
● 混合工程与持续集成
● 快速完成混合工程搭建
● 使用混合栈框架开发
第二章 能力增强
● 基于原生能力的插件扩展
● 基于外接纹理的同层渲染
● 多媒体能力扩展实践
● 富文本能力应用实践
第三章 业务架构设计
● 应用框架设计实践
● 轻量级动态化渲染引擎的设计
● 面向切面编程的设计实践
● 高性能的动态模板渲染实践
第四章 数据统计与性能
● 数据统计框架的设计
● 性能稳定性监控方案的设计
● 高可用框架的设计与实践
● 跨端方案性能对比实践
第五章 企业级应用实战
● 基于Flutter的端结构演进与创新
● Flutter与FaaS云端一体化架构
由于文章内容比较多,篇幅有限,资料已经被整理成了PDF文档,有需要 Flutter技术解析与实战 完整文档的可扫描下方卡片免费获取!
《Flutter进阶学习笔记》
目录
第一章 为什么 Flutter 是跨平台开发的终极之选
● 这是为什么?
● 跨平台开发
● 什么是Flutter
● Flutter特性
● Flutter 构建应用的工具
● 使用 Flutter 构建的热门应用
● 构建 Flutter 应用的成本
第二章 在Windows上搭建Flutter开发环境
● 使用镜像
● 系统要求
● 获取Flutter SDK
● 编辑器设置
● Android设置
● 起步: 配置编辑器
● 起步: 体验
● 体验热重载
第三章 编写您的第一个 Flutter App
● 创建 Flutter app
● 使用外部包(package)
● 添加一个 有状态的部件(Stateful widget)
● 创建一个无限滚动ListView
● 添加交互
● 导航到新页面
● 使用主题更改UI
第四章 Flutter开发环境搭建和调试
● 开发环境的搭建
● 模拟器的安装与调试
● 开发环境的搭建
● 模拟器的安装与调试
第五章 Dart语法篇之基础语法(一)
● 简述
● Hello Dart
● 数据类型
● 变量和常量
● 集合(List、Set、Map)
● 流程控制
● 运算符
● 异常
● 函数
● 总结
第六章 Dart语法篇之集合的使用与源码解析(二)
● List
● Set
● Map
● Queue
● LinkedList
● HashMap
● Map、HashMap、LinkedHashMap、SplayTreeMap区别
● 命名构造函数from和of的区别以及使用建议
第七章 Dart语法篇之集合操作符函数与源码分析(三)
● 简述
● Iterable
● forEach
● map
● any
● every
● where
● firstWhere和singleWhere和lastWhere
● join
● take
● takeWhile
● skip
● skipWhile
● follwedBy
● expand
● reduce
● elementAt
第八章 Dart语法篇之函数的使用(四)
● 简述
● 函数参数
● 匿名函数(闭包,lambda)
● 箭头函数
● 局部函数
● 顶层函数和静态函数
● main函数
● Function函数对象
第九章 Dart语法篇之面向对象基础(五)
● 简述
● 属性访问器(accessor)函数setter和getter
● 面向对象中的变量
● 构造函数
● 抽象方法、抽象类和接口
● 类函数
● 总结
第十章 Dart语法篇之面向对象继承和Mixins(六**)**
● 简述
● 类的单继承
● 基于Mixins的多继承
● 总结
第十一章 Dart语法篇之类型系统与泛型(七)
● 简述
● 可选类型
● 接口类型
● 泛型
● 类型具体化
● 总结
第十二章 Flutter中的widget
● Flutter页面-基础Widget
● Widget
● StatelessWidget
● State生命周期
● 基础widget
● DefaultTextStyle
● FlutterLogo
● Icon
● Iamge.asset
● CircleAvatar
● FadeInImage
● 按钮
● FlatButton
● OutlineButton
● TextFormField
由于文章内容比较多,篇幅有限,资料已经被整理成了PDF文档,有需要 Flutter技术解析与实战 完整文档的可扫描下方卡片免费获取!
《Flutter入门与实战》
目录
第一章、Flutter基本功能
● 我的第一个 Flutter 应用之旅
● 容器的盒子模型
● 构建一个常用的页面框架
● 设置 App 的主色调与字体
● 来一个图文并茂的列表
● 给列表增加下拉刷新和上滑加载更多功能
● 使用cached_network_image 优化图片加载体验
● 仿一个微信价值几个亿的页面
● 开发一个常用的登录页面
● 封装一个通用的文本输入框
● 底部弹窗ModelBottomSheet详解
● 利用CustomScrollView实现更有趣的滑动效果
● 底部弹窗如何实现多项选择?
第二章、Flutter路由管理
● App页面路由及路由拦截实现
● 路由参数处理
● 初识 fluro 路由管理
● 使用 fluro 的转场动画提高页面切换体验
● 使用自定义转场动画实现个性化页面切换
● 此路是我开,此树是我栽。若是没权限,403到来
● Flutter 2.0的路由把我搞蒙了
● 山路十八弯的2.0路由
第三章、Flutter网络请求插件Dio
● 初次见面,网络请求王者之dio
● 利用 Dio请求删除数据
● 使用 Dio的 Patch请求完成详情编辑
● 使用 Post 请求增加动态
● 一文搞定图片选择及图片上传
● 使用 GetIt 同步不同页面间数据
● Dio 封装之金屋藏娇
● Dio 之拦截器
● Dio之戛然而止
● 从源码深入了解Dio 的
● 小伙子,你买票了吗?
● 手写一个持久化的
● Dio之文件下载
● Dio 篇章总结
第四章、Flutter状态管理
● 基础原理篇
● Provider篇
● Redux篇
● Mobx篇
● Getx篇
● BLOC篇
● 状态管理系列大汇总
第五章、Flutter 动画
● 使用 Animation 构建爱心三连动画
● 让你的组件拥有三维动效
● 小姐姐渐现效果 ——AnimatedOpacity 使用
● 使用 AnimatedBuilder分离组件和动画,实现动效复用
● 看这一颗跳动的热心—— AnimatedPadding 应用
● 使用AnimatedSwitcher 做场景切换
● 给小姐姐的照片调个颜色滤镜
由于文章内容比较多,篇幅有限,资料已经被整理成了PDF文档,有需要 Flutter技术解析与实战 完整文档的可扫描下方卡片免费获取!
# 《Flutter完整开发实战详解》目录
第一章 Dart语言和Flutter基础
第二章 快速开发实战篇
第三章 打包与填坑篇
第四章 Redux、主题、国际化
第五章 深入探索
第六章 深入Widget原理
第七章 深入布局原理
第八章 实用技巧与填坑
第九章 深入绘制原理
第十章 深入图片加载流程
第十一章 全面深入理解Stream
第十二章 全面深入理解状态管理设计
第十三章 全面深入触摸和滑动原理
第十四章 混合开发打包 Android 篇
l Flutter 面试知识点集锦
l Flutter 开发实战与前景展望 - RTC Dev Meetup
由于文章内容比较多,篇幅有限,资料已经被整理成了PDF文档,有需要 Flutter技术解析与实战 完整文档的可扫描下方卡片免费获取!
**更有更多资料,加微信免费领取**