flutter开发实战-创建一个微光加载效果

flutter开发实战-创建一个微光加载效果

当加载数据的时候,loading是必不可少的。从用户体验(UX)的角度来看,最重要的是向用户展示加载正在进行。向用户传达数据正在加载的一种流行方法是在与正在加载的内容类型近似的形状上显示带有微光动画的铬色。
在这里插入图片描述
微光加载效果需要用到的是ShaderMask.

一、引入ShaderMask

将[着色器]生成的遮罩应用于其子对象的小部件。

ShaderMask(shaderCallback: (Rect bounds) {return RadialGradient(center: Alignment.topLeft,radius: 1.0,colors: <Color>[Colors.yellow, Colors.deepOrange.shade900],tileMode: TileMode.mirror,).createShader(bounds);},child: const Text('I’m burning the memories'),
)

二、微光加载效果

使用ShaderMask微光加载效果,通过gradient.createShader控制微光的范围

return ShaderMask(blendMode: BlendMode.srcATop,shaderCallback: (bounds) {return gradient.createShader(Rect.fromLTWH(-offsetWithinShimmer.dx,-offsetWithinShimmer.dy,shimmerSize.width,shimmerSize.height,),);},child: widget.child,);

创建一个微光加载效果完整代码如下


const _shimmerGradient = LinearGradient(colors: [Color(0xFFEBEBF4),Color(0xFFF4F4F4),Color(0xFFEBEBF4),],stops: [0.1,0.3,0.4,],begin: Alignment(-1.0, -0.3),end: Alignment(1.0, 0.3),tileMode: TileMode.clamp,
);class ExampleUiLoadingAnimation extends StatefulWidget {const ExampleUiLoadingAnimation({super.key,});@overrideState<ExampleUiLoadingAnimation> createState() =>_ExampleUiLoadingAnimationState();
}class _ExampleUiLoadingAnimationState extends State<ExampleUiLoadingAnimation> {bool _isLoading = true;void _toggleLoading() {setState(() {_isLoading = !_isLoading;});}@overrideWidget build(BuildContext context) {return Scaffold(body: Shimmer(linearGradient: _shimmerGradient,child: ListView(physics: _isLoading ? const NeverScrollableScrollPhysics() : null,children: [const SizedBox(height: 16),_buildTopRowList(),const SizedBox(height: 16),_buildListItem(),_buildListItem(),_buildListItem(),],),),floatingActionButton: FloatingActionButton(onPressed: _toggleLoading,child: Icon(_isLoading ? Icons.hourglass_full : Icons.hourglass_bottom,),),);}Widget _buildTopRowList() {return SizedBox(height: 72,child: ListView(physics: _isLoading ? const NeverScrollableScrollPhysics() : null,scrollDirection: Axis.horizontal,shrinkWrap: true,children: [const SizedBox(width: 16),_buildTopRowItem(),_buildTopRowItem(),_buildTopRowItem(),_buildTopRowItem(),_buildTopRowItem(),_buildTopRowItem(),],),);}Widget _buildTopRowItem() {return ShimmerLoading(isLoading: _isLoading,child: const CircleListItem(),);}Widget _buildListItem() {return ShimmerLoading(isLoading: _isLoading,child: CardListItem(isLoading: _isLoading,),);}
}class Shimmer extends StatefulWidget {static ShimmerState? of(BuildContext context) {return context.findAncestorStateOfType<ShimmerState>();}const Shimmer({super.key,required this.linearGradient,this.child,});final LinearGradient linearGradient;final Widget? child;@overrideShimmerState createState() => ShimmerState();
}class ShimmerState extends State<Shimmer> with SingleTickerProviderStateMixin {late AnimationController _shimmerController;@overridevoid initState() {super.initState();_shimmerController = AnimationController.unbounded(vsync: this)..repeat(min: -0.5, max: 1.5, period: const Duration(milliseconds: 1000));}@overridevoid dispose() {_shimmerController.dispose();super.dispose();}LinearGradient get gradient => LinearGradient(colors: widget.linearGradient.colors,stops: widget.linearGradient.stops,begin: widget.linearGradient.begin,end: widget.linearGradient.end,transform:_SlidingGradientTransform(slidePercent: _shimmerController.value),);bool get isSized =>(context.findRenderObject() as RenderBox?)?.hasSize ?? false;Size get size => (context.findRenderObject() as RenderBox).size;Offset getDescendantOffset({required RenderBox descendant,Offset offset = Offset.zero,}) {final shimmerBox = context.findRenderObject() as RenderBox?;return descendant.localToGlobal(offset, ancestor: shimmerBox);}Listenable get shimmerChanges => _shimmerController;@overrideWidget build(BuildContext context) {return widget.child ?? const SizedBox();}
}class _SlidingGradientTransform extends GradientTransform {const _SlidingGradientTransform({required this.slidePercent,});final double slidePercent;@overrideMatrix4? transform(Rect bounds, {TextDirection? textDirection}) {return Matrix4.translationValues(bounds.width * slidePercent, 0.0, 0.0);}
}class ShimmerLoading extends StatefulWidget {const ShimmerLoading({super.key,required this.isLoading,required this.child,});final bool isLoading;final Widget child;@overrideState<ShimmerLoading> createState() => _ShimmerLoadingState();
}class _ShimmerLoadingState extends State<ShimmerLoading> {Listenable? _shimmerChanges;@overridevoid didChangeDependencies() {super.didChangeDependencies();if (_shimmerChanges != null) {_shimmerChanges!.removeListener(_onShimmerChange);}_shimmerChanges = Shimmer.of(context)?.shimmerChanges;if (_shimmerChanges != null) {_shimmerChanges!.addListener(_onShimmerChange);}}@overridevoid dispose() {_shimmerChanges?.removeListener(_onShimmerChange);super.dispose();}void _onShimmerChange() {if (widget.isLoading) {setState(() {// Update the shimmer painting.});}}@overrideWidget build(BuildContext context) {if (!widget.isLoading) {return widget.child;}// Collect ancestor shimmer info.final shimmer = Shimmer.of(context)!;if (!shimmer.isSized) {// The ancestor Shimmer widget has not laid// itself out yet. Return an empty box.return const SizedBox();}final shimmerSize = shimmer.size;final gradient = shimmer.gradient;final offsetWithinShimmer = shimmer.getDescendantOffset(descendant: context.findRenderObject() as RenderBox,);return ShaderMask(blendMode: BlendMode.srcATop,shaderCallback: (bounds) {return gradient.createShader(Rect.fromLTWH(-offsetWithinShimmer.dx,-offsetWithinShimmer.dy,shimmerSize.width,shimmerSize.height,),);},child: widget.child,);}
}//----------- List Items ---------
class CircleListItem extends StatelessWidget {const CircleListItem({super.key});@overrideWidget build(BuildContext context) {return Padding(padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),child: Container(width: 54,height: 54,decoration: const BoxDecoration(color: Colors.black,shape: BoxShape.circle,),child: ClipOval(child: Image.network('https://docs.flutter.dev/cookbook''/img-files/effects/split-check/Avatar1.jpg',fit: BoxFit.cover,),),),);}
}class CardListItem extends StatelessWidget {const CardListItem({super.key,required this.isLoading,});final bool isLoading;@overrideWidget build(BuildContext context) {return Padding(padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),child: Column(crossAxisAlignment: CrossAxisAlignment.start,children: [_buildImage(),const SizedBox(height: 16),_buildText(),],),);}Widget _buildImage() {return AspectRatio(aspectRatio: 16 / 9,child: Container(width: double.infinity,decoration: BoxDecoration(color: Colors.black,borderRadius: BorderRadius.circular(16),),child: ClipRRect(borderRadius: BorderRadius.circular(16),child: Image.network('https://docs.flutter.dev/cookbook''/img-files/effects/split-check/Food1.jpg',fit: BoxFit.cover,),),),);}Widget _buildText() {if (isLoading) {return Column(crossAxisAlignment: CrossAxisAlignment.start,children: [Container(width: double.infinity,height: 24,decoration: BoxDecoration(color: Colors.black,borderRadius: BorderRadius.circular(16),),),const SizedBox(height: 16),Container(width: 250,height: 24,decoration: BoxDecoration(color: Colors.black,borderRadius: BorderRadius.circular(16),),),],);} else {return const Padding(padding: EdgeInsets.symmetric(horizontal: 8),child: Text('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do ''eiusmod tempor incididunt ut labore et dolore magna aliqua.',),);}}
}

三、小结

flutter开发实战-创建一个微光加载效果

学习记录,每天不停进步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/28931.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

货代小白快来收藏‼️普货与非普货的区别

普货是指不属于以下类别的普通货物 危险品 冷冻/冷藏品 违禁品 仿牌货 敏感货 危险品 危险品具体分为九类&#xff1a; 爆炸品 压缩气体 易燃液体 易燃固体、易燃物品和遇湿易燃物品 氧化剂和有机氧化物 有毒和感染性物品 放射性 腐蚀性 杂类 冷冻/冷藏品 主要是指以食品为主的…

简述spock以及使用

1. 介绍 1.1 Spock是什么&#xff1f; Spock是一款国外优秀的测试框架&#xff0c;基于BDD&#xff08;行为驱动开发&#xff09;思想实现&#xff0c;功能非常强大。Spock结合Groovy动态语言的特点&#xff0c;提供了各种标签&#xff0c;并采用简单、通用、结构化的描述语言…

php配合fiddler批量下载淘宝天猫商品数据分享

有个做电商的朋友问我,每次上款,需要手动去某宝去搬运商品图片视频,问我能不能帮忙写个脚本,朋友开口了,那就尝试一下 首先打开某宝,访问一款商品,找出他的数据来源 通过观察我们发现主图数据来这个接口输出 h5api.m.taobao.com/h5/mtop.taobao.pcdetail.data.get/1.0 …

如何学习创建和使用 Java 归档(JAR)文件

1. 简介 JAR&#xff08;Java ARchive&#xff09;文件是一种用于打包多个Java类、资源文件和元数据的压缩文件格式。它在Java开发和发布过程中扮演着重要角色。通过使用JAR文件&#xff0c;开发者可以将应用程序的所有组件打包在一个文件中&#xff0c;方便分发和部署。 2. …

世界森林覆盖率分布图

原文链接https://mp.weixin.qq.com/s?__bizMzUyNzczMTI4Mg&mid2247680287&idx1&sn6ac57fa7472fc58cad1d5ab11b1d6b3b&chksmfa775e22cd00d7341e4f59d52221fb7f9a8e2d83602ab58719481af66b2f3b153c57f01c68bb&token808263816&langzh_CN&scene21#wec…

开源语音合成模型ChatTTS本地部署结合内网穿透实现远程访问

文章目录 前言1. 下载运行ChatTTS模型2. 安装Cpolar工具3. 实现公网访问4. 配置ChatTTS固定公网地址 前言 本篇文章就教大家如何快速地在Windows中本地部署ChatTTS&#xff0c;并且我们还可以结合Cpolar内网穿透实现公网随时随地访问ChatTTS AI语言模型。 最像人声的AI来了&a…

Airflow任务流调度

0 前言 Airflow是Airbnb内部发起的一个工作流管理平台。使用Python编写实现的任务管理、调度、监控工作流平台。Airflow的调度依赖于crontab命令&#xff0c;与crontab相比&#xff0c;Airflow可以方便地查看任务的执行状况&#xff08;执行是否成功、执行时间、执行依赖等&…

基于OCC+OSG的读取IGS模型显示其装配以及模型颜色

一般来说&#xff0c;读取STP模型会解析其装配结构&#xff0c;而读取IGS模型时候一般不这么做&#xff0c;因为IGS的每个部件大多是面片&#xff0c;而非一个实体模型&#xff0c;所以比如一些开源软件&#xff0c;比如Freecad等都是直接将模型作为一个整体并且在模型树上只显…

Elixir学习笔记——try, catch, and rescue

Elixir 有三种错误机制&#xff1a;errors, throws, and exits。在本章中&#xff0c;我们将探索每种机制&#xff0c;并说明何时应使用它们。 Errors 当代码中发生异常时&#xff0c;就会使用错误&#xff08;或异常&#xff09;。可以通过尝试将数字添加到原子来检索示例错…

生活好物:日常更精彩

我们的日用杂货店&#xff0c;是生活美学的聚集地。这里汇聚了各式各样的生活用品&#xff0c;每一件都蕴含着对生活的热爱与追求。 走进我们的日用杂货店&#xff0c;仿佛打开了一个充满生活气息的宝藏盒。从厨房的锅碗瓢盆&#xff0c;到浴室的洗漱用品&#xff0c;再到客厅的…

6.17 作业

使用qt实现优化自己的登录界面 要求&#xff1a; 1. qss实现 2. 需要有图层的叠加 &#xff08;QFrame&#xff09; 3. 设置纯净窗口后&#xff0c;有关闭等窗口功能。 4. 如果账号密码正确&#xff0c;则实现登录界面关闭&#xff0c;另一个应用界面显示。 第一个源文件 …

9.无代码爬虫软件做网页数据抓取流程——弹出窗口的移除

首先&#xff0c;多数情况下免费版本的功能&#xff0c;已经可以满足绝大多数采集需求&#xff0c;想了解八爪鱼采集器版本区别的详情&#xff0c;请访问这篇帖子&#xff1a; https://blog.csdn.net/cctv1123/article/details/139581468 八爪鱼采集器免费版和个人版、团队版下…

反射复习(java)

文章目录 反射机制的作用反射机制的原理加载机制详细解释 获取 Class 对象反射获取构造方法&#xff1a;获取 Class 对象里面 Constructor 对象反射获取成员变量&#xff1a;获取Class 对象里面的 Field 对象反射获取成员方法&#xff1a;获取 Class 对象里的 Method 对象其他常…

15.编写自动化测试(下)

标题 三、控制测试流程3.1 添加测试参数3.2 并行或连续运行测试3.3 显示函数输出3.4 指定/过滤测试用例名称3.5 忽略某些测试用例3.6 只运行被忽略的测试 四、测试的组织结构4.1 概念引入4.2 测试私有函数4.2 单元测试4.3 集成测试4.4 集成测试中的子模块4.5 二进制crate的集成…

Python脚本中使用 if 语句导致的错误代码

在 Python 脚本中使用 if 语句是一种常见的控制流程结构&#xff0c;用于根据条件决定程序的执行路径。当使用 Python 中的 if 语句时&#xff0c;可能会导致一些常见的错误。下面就是我经常遇到的错误代码示例及其可能的原因和解决方法&#xff0c;希望对大家有些帮助&#xf…

死锁预防之银行家算法

死锁预防之银行家算法 第一章 概述 Dijkstra提出了一种能够避免死锁的调度算法,称为银行家算法。 它的模型基于一个小城镇的银行家,他向一群客户分别承诺了一定的贷款额度,每个客户都有一个贷款额度,银行家知道不可能所有客户同时都需要最大贷款额,所以他只保留一定单位…

韩国职场新趋势:员工拒绝晋升,追求工作与生活的平衡

在当前职场环境中&#xff0c;晋升通常被视为职业生涯发展的重要里程碑。然而&#xff0c;据韩国《今日财经》报道&#xff0c;现代重工工会在今年的劳资谈判中提出了一个令人关注的要求——“拒绝晋升权”。这一要求反映了韩国职场的新趋势&#xff0c;即越来越多的员工对高薪…

长期保存红酒的挑战与应对策略

云仓酒庄雷盛红酒&#xff0c;以其卓着的品质和口感&#xff0c;赢得了无数葡萄酒爱好者的喜爱。然而&#xff0c;对于那些希望长期保存这些珍贵佳酿的人来说&#xff0c;如何确保红酒的品质和风味不受时间的影响&#xff0c;却是一项充满挑战的任务。 长期保存红酒的大挑战来自…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 火星字符串(100分) - 三语言AC题解(Python/Java/Cpp)

&#x1f36d; 大家好这里是清隆学长 &#xff0c;一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 &#x1f4bb; ACM银牌&#x1f948;| 多次AK大厂笔试 &#xff5c; 编程一对一辅导 &#x1f44f; 感谢大家的订阅➕ 和 喜欢&#x1f497; &#x1f…

电影《加菲猫家族》观后感

上周看了电影《加菲猫家族》&#xff0c;本片其中有很多明亮的画面&#xff0c;相关艳丽的色彩&#xff0c;充满温馨的场景&#xff0c;很符合加菲猫的一贯画风&#xff0c;即使反派出场时&#xff0c;带有阴暗的感觉&#xff0c;看起也不是特别吓人&#xff0c;比较欢乐气氛&a…