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.xdnf.cn/news/1451134.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Android Room数据库使用介绍

1.简介 Room是Google提供的Android架构组件之一&#xff0c;旨在简化数据库操作。它是SQLite的一个抽象层&#xff0c;提供了更易用和安全的API。 Room的总体架构: 2.Room数据库的基础概念 Entity Entity是Room中的数据表&#xff0c;每个Entity类对应一个SQLite表。 DAO …

队列——Acwing.829模拟队列

队列 定义 队列是一种特殊的线性表&#xff0c;遵循先进先出&#xff08;First In First Out&#xff0c;FIFO&#xff09;的原则。可以进行入队&#xff08;在队尾添加元素&#xff09;和出队&#xff08;从队首移除元素&#xff09;操作。 运用情况 任务调度&#xff1a;…

ES6+Vue

ES6Vue ES6语法 ​ VUE基于是ES6的&#xff0c;所以在使用Vue之前我们需要先了解一下ES6的语法。 1.什么是ECMAScript6 ECMAScript是浏览器脚本语言的规范&#xff0c;基于javascript来制定的。为什么会出现这个规范呢&#xff1f; 1.1.JS发展史 1995年&#xff0c;网景工…

大模型赛道有前景吗?

前言 随着人工智能技术的飞速发展&#xff0c;大模型作为新一代AI技术的核心驱动力&#xff0c;正在全球范围内掀起一场科技革命。在这个浪潮中&#xff0c;大模型赛道以其巨大的发展潜力、广泛的应用前景&#xff0c;成为了众多企业和投资者关注的焦点。本文将从多个角度探讨…

【STM32进阶笔记】GPIO端口

前段时间由于其他原因&#xff0c;专栏暂停更新了较长一段时间&#xff0c;现在恢复更新&#xff0c;争取继续为大家创造有价值的内容&#xff0c;期待大家的订阅关注&#xff0c;欢迎互相学习交流。 在STM32速成笔记系列专栏中其实已经对GPIO的一些必要知识进行了介绍&#xf…

tvm实战踩坑

今天玩了一下tvm的安装 我要安装v0.14.0的版本 所以按照官网的方法 https://tvm.apache.org/docs/install/from_source.html#python-package-installation git clone --recursive https://github.com/apache/tvm tvmgit checkout v0.14.0recursive是很重要的 这一步可以替换成…

数栈xAI:轻量化、专业化、模块化,四大功能革新 SQL 开发体验

在这个数据如潮的时代&#xff0c;SQL 已远远超越了简单的查询语言范畴&#xff0c;它已成为数据分析和决策制定的基石&#xff0c;成为撬动企业智慧决策的关键杠杆。SQL 的编写和执行效率直接关系到数据处理的速度和分析结果的深度&#xff0c;对企业洞察市场动态、优化业务流…

[Shell编程学习路线]——探讨Shell中变量的作用范围(export)

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f6e0;️Shell编程专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年6月14日10点14分 &#x1f004;️文章质量&#xff1a;95分 文章目录 ————前言———— 定义变量&#xff1a; 输出变…

SpringBoot3 整合 Mybatis 完整版

本文记录一下完整的 SpringBoot3 整合 Mybatis 的步骤。 只要按照本步骤来操作&#xff0c;整合完成后就可以正常使用。1. 添加数据库驱动依赖 以 MySQL 为例。 当不指定 依赖版本的时候&#xff0c;会 由 springboot 自动管理。 <dependency><groupId>com.mysql&l…

第2章 Rust初体验7/8:错误处理时不关心具体错误类型的下划线:提高代码可读性:猜骰子冷热游戏

讲动人的故事,写懂人的代码 2.6.6 用as进行类型转换:显式而简洁的语法 贾克强:“大家在查看Rust代码时,可能会注意到这一句。在这里,如果我们不使用as i32,编译器会报错,因为它在u32中找不到abs()方法。这是因为prev和sum_of_two_dice都是u32类型,u32类型并不支持abs(…

燃气守护神:燃气管网安全运行监测解决方案

在这个智能科技日新月异的时代&#xff0c;燃气安全却时有发生&#xff0c;严重危害人们的生命财产安全&#xff0c;因此旭华智能根据相关政策要求并结合自身优势&#xff0c;打造了一套燃气管网安全运行监测解决方案&#xff0c;他犹如一位“燃气守护神”&#xff0c;悄然守护…

[深度学习]基于C++和onnxruntime部署yolov10的onnx模型

基于C和ONNX Runtime部署YOLOv10的ONNX模型&#xff0c;可以遵循以下步骤&#xff1a; 准备环境&#xff1a;首先&#xff0c;确保已经下载后指定版本opencv和onnruntime的C库。 模型转换&#xff1a;按照官方源码&#xff1a;https://github.com/THU-MIG/yolov10 安装好yolov…

【linux网络(三)】HTTP协议详解

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:Linux从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学更多操作系统知识   &#x1f51d;&#x1f51d; Linux网络 1. 前言2. 序列化和…

新面貌、新功能、新内容!禅道官网改版升级,全面提升用户体验

为了给用户更好的体验&#xff0c;禅道团队于23年6月与艾体验团队达成合作&#xff0c;正式启动了禅道官网改版的项目&#xff0c;历经一年的努力&#xff0c;2024年6月7日&#xff0c;禅道新官网顺利完成改版升级&#xff0c;正式上线与大家见面啦&#xff01; 此次改版上线的…

LeetCode 2813.子序列最大优雅度

给你一个长度为 n 的二维整数数组 items 和一个整数 k 。 items[i] [profiti, categoryi]&#xff0c;其中 profiti 和 categoryi 分别表示第 i 个项目的利润和类别。 现定义 items 的 子序列 的 优雅度 可以用 total_profit distinct_categories^2 计算&#xff0c;其中 t…

腾讯云EdgeOne对比普通CDN的分别

EdgeOne架构图 普通CDN架构图 ​​​​​​​ 腾讯云EdgeOne对比普通CDN的不同点 服务范围和集成度 腾讯云EdgeOne是一体化的综合平台&#xff0c;不仅提供内容分发功能&#xff0c;还包括安全防护、性能优化和边缘计算等服务。EdgeOne提供了DDoS防护、WAF&#xff08;Web应…

Tailwind CSS 响应式设计实战指南

title: Tailwind CSS 响应式设计实战指南 date: 2024/6/13 updated: 2024/6/13 author: cmdragon excerpt: 这篇文章介绍了如何运用Tailwind CSS框架创建响应式网页设计&#xff0c;涵盖博客、电商网站及企业官网的布局实例&#xff0c;包括头部导航、内容区域、侧边栏、页脚…

Java-多线程

概念 进程&#xff1a;程序的基本执行实体 线程&#xff1a;操作系统能够进行运算调度的最小单位&#xff0c;被包含在进程之中&#xff0c;是进程的实际运作单位 并发&#xff1a;同一时刻&#xff0c;多个指令在单个CPU上交替执行。 并行&#xff1a;同一时刻&#xff0c;多…

阿里云 Ubuntu 22.04.4 LTS 安装postfix+dovecot 搭建邮件服务器

一 安装 1安装postfix sudo apt-get install postfix #如果没有弹出配置界面&#xff0c;运行 dpkg-reconfigure postfix #sudo vim /etc/postfix/main.cf smtpd_banner $myhostname ESMTP $mail_name (Ubuntu) biff no append_dot_mydomain no readme_directory no co…

求和路径00

题目链接 求和路径 题目描述 注意点 节点总数 < 10000节点的值可能是正数或负数路径不一定非得从二叉树的根节点或叶节点开始或结束&#xff0c;但是其方向必须向下(只能从父节点指向子节点方向) 解答思路 因为要求树的路径和&#xff0c;所以初始想到的是深度优先遍历…