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

相关文章

使用Python开发一个简单的本地图片服务器

《使用Python开发一个简单的本地图片服务器》本文介绍了如何结合wxPython构建的图形用户界面GUI和Python内建的Web服务器功能,在本地网络中搭建一个私人的,即开即用的网页相册,文中的示... 目录项目目标核心技术栈代码深度解析完整代码工作流程主要功能与优势潜在改进与思考运行结果总结你是否曾经

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis

MyBatis 动态 SQL 优化之标签的实战与技巧(常见用法)

《MyBatis动态SQL优化之标签的实战与技巧(常见用法)》本文通过详细的示例和实际应用场景,介绍了如何有效利用这些标签来优化MyBatis配置,提升开发效率,确保SQL的高效执行和安全性,感... 目录动态SQL详解一、动态SQL的核心概念1.1 什么是动态SQL?1.2 动态SQL的优点1.3 动态S

Spring Boot 配置文件之类型、加载顺序与最佳实践记录

《SpringBoot配置文件之类型、加载顺序与最佳实践记录》SpringBoot的配置文件是灵活且强大的工具,通过合理的配置管理,可以让应用开发和部署更加高效,无论是简单的属性配置,还是复杂... 目录Spring Boot 配置文件详解一、Spring Boot 配置文件类型1.1 applicatio

Python基于wxPython和FFmpeg开发一个视频标签工具

《Python基于wxPython和FFmpeg开发一个视频标签工具》在当今数字媒体时代,视频内容的管理和标记变得越来越重要,无论是研究人员需要对实验视频进行时间点标记,还是个人用户希望对家庭视频进行... 目录引言1. 应用概述2. 技术栈分析2.1 核心库和模块2.2 wxpython作为GUI选择的优

Pandas使用SQLite3实战

《Pandas使用SQLite3实战》本文主要介绍了Pandas使用SQLite3实战,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录1 环境准备2 从 SQLite3VlfrWQzgt 读取数据到 DataFrame基础用法:读

Flutter打包APK的几种方式小结

《Flutter打包APK的几种方式小结》Flutter打包不同于RN,Flutter可以在AndroidStudio里编写Flutter代码并最终打包为APK,本篇主要阐述涉及到的几种打包方式,通... 目录前言1. android原生打包APK方式2. Flutter通过原生工程打包方式3. Futte

idea中创建新类时自动添加注释的实现

《idea中创建新类时自动添加注释的实现》在每次使用idea创建一个新类时,过了一段时间发现看不懂这个类是用来干嘛的,为了解决这个问题,我们可以设置在创建一个新类时自动添加注释,帮助我们理解这个类的用... 目录前言:详细操作:步骤一:点击上方的 文件(File),点击&nbmyHIgsp;设置(Setti

利用Python开发Markdown表格结构转换为Excel工具

《利用Python开发Markdown表格结构转换为Excel工具》在数据管理和文档编写过程中,我们经常使用Markdown来记录表格数据,但它没有Excel使用方便,所以本文将使用Python编写一... 目录1.完整代码2. 项目概述3. 代码解析3.1 依赖库3.2 GUI 设计3.3 解析 Mark

利用Go语言开发文件操作工具轻松处理所有文件

《利用Go语言开发文件操作工具轻松处理所有文件》在后端开发中,文件操作是一个非常常见但又容易出错的场景,本文小编要向大家介绍一个强大的Go语言文件操作工具库,它能帮你轻松处理各种文件操作场景... 目录为什么需要这个工具?核心功能详解1. 文件/目录存javascript在性检查2. 批量创建目录3. 文件