简介
在应用程序开发中,加载时间是不可避免的。从用户体验 (UX) 的角度来看,最重要的是向用户展示正在加载。向用户传达数据正在加载的一种流行方法是在近似加载的内容类型的形状上显示带有微光动画的镀铬颜色。
Shimmer 用于在应用程序中从服务器加载内容时添加精彩的动画。这使 UI 看起来更具响应性。它可以很好地被利用,而不是传统的 ProgressBar 或 Flutter 结构中可访问的常见loading。
适用场景
商品列表、我的收藏、预售活动、商品详情等类似页面。
效果图
商品列表页 我的收藏
微光动画效果属性介绍
|
属性
|
描述
|
|
baseColor
|
显示在 Widget 上的 Shimmer 的基本颜色
|
|
highlightColor
|
提供微光般效果的颜色。这种颜色继续在子小部件上波动,并产生微光效果
|
|
child
|
创建 ShimmerEffect 所需的任何小部件
|
|
direction
|
调整微光高光颜色的方向。从左到右、从右到左、从开始到结束或从底到顶
|
|
period
|
控制微光效果的速度。默认1500毫秒
|
具体实现
1.添加依赖-pubspec.yaml
shimmer: ^2.0.0
2.创建微光动画Widget-ShimmerLoading
import 'package:flutter/material.dart';
import 'package:shimmer/shimmer.dart';
/// @author: niumenglin
/// @time: 2021/11/29-2:40 下午
/// @Email: menglin.nml@ncarzone.com
/// @desc:Flutter 微光动画效果
class ShimmerLoading extends StatelessWidget {
final double width;
final double height;
final ShapeBorder shapeBorder;
///方形
const ShimmerLoading.rectangular(
{this.width = double.infinity, required this.height})
: this.shapeBorder = const RoundedRectangleBorder();
///圆形
const ShimmerLoading.circular(
{this.width = double.infinity,
required this.height,
this.shapeBorder = const CircleBorder()});
@override
Widget build(BuildContext context) => Shimmer.fromColors(
baseColor: Colors.grey[300]!,
highlightColor: Colors.grey[100]!,
period: Duration(seconds: 2),
child: Container(
width: width,
height: height,
decoration: ShapeDecoration(
color: Colors.grey[400]!,
shape: shapeBorder,
),
),
);
}
3.创建通用商品Item微光加载Widget
备注:如果通用的Widget与某个页面完全不一致,需要单独定义一套。将原有item布局的组件统一替换成ShimmerLoading.rectangular或ShimmerLoading.circular即可。
import 'package:flutter/material.dart';
import 'package:flutter_yonline/widget/shimmer/shimmer_loading.dart';
/// @author: niumenglin
/// @time: 2021/11/29-2:45 下午
/// @Email: menglin.nml@ncarzone.com
/// @desc:通用商品Item 微光加载布局
class CommonProductItemShimmer extends StatefulWidget {
const CommonProductItemShimmer({Key? key}) : super(key: key);
@override
_CommonProductItemShimmerState createState() =>
_CommonProductItemShimmerState();
}
class _CommonProductItemShimmerState extends State<CommonProductItemShimmer> {
@override
Widget build(BuildContext context) {
return Column(
children: [
Container(
color: Colors.white,
padding: EdgeInsets.all(10),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ShimmerLoading.rectangular(width: 85, height: 85),
Expanded(
child: Container(
margin: EdgeInsets.only(left: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ShimmerLoading.rectangular(height: 16),
SizedBox(
height: 10,
),
Container(
margin: EdgeInsets.only(top: 10),
child:
ShimmerLoading.rectangular(width: 140, height: 14),
),
SizedBox(
height: 10,
),
ShimmerLoading.rectangular(width: 80, height: 18),
SizedBox(
height: 10,
),
ShimmerLoading.rectangular(height: 12),
]),
))
],
),
),
Divider(
height: 10,
indent: 10,
color: Color(0xffD8D8D8),
)
],
);
}
}
4.定义一个全局bool值,是否是初始化加载标识
比如:bool _initLoading=true。默认为true;网络请求回调后,将其置为false。
5.build绘制列表页时处理
5.1 _initLoading = true 场景
- 设置ListView的itemCount属性,itemCount>=一个屏幕的可见数量;
- 设置itemBuilder 即通用的微光加载布局。
if (_initLoading) { return CommonProductItemShimmer();}
5.2 _initLoading = false 场景
- 设置ListView的itemCount属性,xxxList集合长度
- 设置itemBuilder 即你原本创建的item布局。
NCZListView(
.....
itemCount: _initLoading ? 10 : model.products.length,
itemBuilder: (_, index) {
if (_initLoading) {
return CommonProductItemShimmer();
}else {
return _buildYourItem();
}
}),