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

2024-06-14 16:20

本文主要是介绍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开发实战-创建一个微光加载效果

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

这篇关于flutter开发实战-创建一个微光加载效果的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1060903

相关文章

Spring框架中@Lazy延迟加载原理和使用详解

《Spring框架中@Lazy延迟加载原理和使用详解》:本文主要介绍Spring框架中@Lazy延迟加载原理和使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录一、@Lazy延迟加载原理1.延迟加载原理1.1 @Lazy三种配置方法1.2 @Component

Python+PyQt5开发一个Windows电脑启动项管理神器

《Python+PyQt5开发一个Windows电脑启动项管理神器》:本文主要介绍如何使用PyQt5开发一款颜值与功能并存的Windows启动项管理工具,不仅能查看/删除现有启动项,还能智能添加新... 目录开篇:为什么我们需要启动项管理工具功能全景图核心技术解析1. Windows注册表操作2. 启动文件

使用Python开发Markdown兼容公式格式转换工具

《使用Python开发Markdown兼容公式格式转换工具》在技术写作中我们经常遇到公式格式问题,例如MathML无法显示,LaTeX格式错乱等,所以本文我们将使用Python开发Markdown兼容... 目录一、工具背景二、环境配置(Windows 10/11)1. 创建conda环境2. 获取XSLT

Flutter实现文字镂空效果的详细步骤

《Flutter实现文字镂空效果的详细步骤》:本文主要介绍如何使用Flutter实现文字镂空效果,包括创建基础应用结构、实现自定义绘制器、构建UI界面以及实现颜色选择按钮等步骤,并详细解析了混合模... 目录引言实现原理开始实现步骤1:创建基础应用结构步骤2:创建主屏幕步骤3:实现自定义绘制器步骤4:构建U

使用Python创建一个功能完整的Windows风格计算器程序

《使用Python创建一个功能完整的Windows风格计算器程序》:本文主要介绍如何使用Python和Tkinter创建一个功能完整的Windows风格计算器程序,包括基本运算、高级科学计算(如三... 目录python实现Windows系统计算器程序(含高级功能)1. 使用Tkinter实现基础计算器2.

SpringBoot中四种AOP实战应用场景及代码实现

《SpringBoot中四种AOP实战应用场景及代码实现》面向切面编程(AOP)是Spring框架的核心功能之一,它通过预编译和运行期动态代理实现程序功能的统一维护,在SpringBoot应用中,AO... 目录引言场景一:日志记录与性能监控业务需求实现方案使用示例扩展:MDC实现请求跟踪场景二:权限控制与

Android开发环境配置避坑指南

《Android开发环境配置避坑指南》本文主要介绍了Android开发环境配置过程中遇到的问题及解决方案,包括VPN注意事项、工具版本统一、Gerrit邮箱配置、Git拉取和提交代码、MergevsR... 目录网络环境:VPN 注意事项工具版本统一:android Studio & JDKGerrit的邮

Python开发文字版随机事件游戏的项目实例

《Python开发文字版随机事件游戏的项目实例》随机事件游戏是一种通过生成不可预测的事件来增强游戏体验的类型,在这篇博文中,我们将使用Python开发一款文字版随机事件游戏,通过这个项目,读者不仅能够... 目录项目概述2.1 游戏概念2.2 游戏特色2.3 目标玩家群体技术选择与环境准备3.1 开发环境3

CentOS和Ubuntu系统使用shell脚本创建用户和设置密码

《CentOS和Ubuntu系统使用shell脚本创建用户和设置密码》在Linux系统中,你可以使用useradd命令来创建新用户,使用echo和chpasswd命令来设置密码,本文写了一个shell... 在linux系统中,你可以使用useradd命令来创建新用户,使用echo和chpasswd命令来设

使用Python和Pyecharts创建交互式地图

《使用Python和Pyecharts创建交互式地图》在数据可视化领域,创建交互式地图是一种强大的方式,可以使受众能够以引人入胜且信息丰富的方式探索地理数据,下面我们看看如何使用Python和Pyec... 目录简介Pyecharts 简介创建上海地图代码说明运行结果总结简介在数据可视化领域,创建交互式地