我正在参加「启航计划」
前语
在前三篇文章中,从为什么要运用Sliver
,再根据运用频率逐一解析Slivers
系列的组件。信任您现已入门了Sliver
的世界。为了更好的将Slivers
相关的组件结合起来运用,本文将经过一个归纳的事例来帮助你了解。
源代码:www.aliyundrive.com/s/mPCDFwRv4…
效果图
话不多说,先上效果图,有图有本相!
页面框架建立
顶部
SliverAppBar(
//指定状态栏(status bar)的亮度为暗色
systemOverlayStyle:
const SystemUiOverlayStyle(statusBarBrightness: Brightness.dark),
expandedHeight: 275.0,
backgroundColor: Colors.white,
elevation: 0.0,
pinned: true,
stretch: true,
flexibleSpace: FlexibleSpaceBar(
background: Image.asset(
'assets/images/back_image.png',
fit: BoxFit.cover,
),
stretchModes: const [
StretchMode.blurBackground,
StretchMode.zoomBackground,
],
),
leadingWidth: 80.0,
//裁剪为圆角矩形
leading: ClipRRect(
borderRadius: BorderRadius.circular(56.0),
//含糊滤镜
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 3.0, sigmaY: 3.0),
child: Container(
height: 56.0,
width: 56.0,
alignment: Alignment.center,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.white.withOpacity(0.20),
),
child: SvgPicture.asset('assets/images/icon/arrow-ios-back-outline.svg'),
),
),
),
);
底部装修
bottom: PreferredSize(
preferredSize: const Size.fromHeight(0.0),
child: Container(
height: 32.0,
alignment: Alignment.center,
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(32.0),
topRight: Radius.circular(32.0),
),
),
child: Container(
width: 40.0,
height: 5.0,
decoration: BoxDecoration(
color: kOutlineColor,
borderRadius: BorderRadius.circular(100.0),
),
),
),
),
运用SliverToBoxAdapter
来运用根据Box
协议的组件
SliverToBoxAdapter(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'意大利面拌42号混凝土',
style: Theme.of(context).textTheme.titleMedium,
),
...
],
),
),
),
经过SliverPersistentHeader
制造菜品展示区域
class Menu extends SliverPersistentHeaderDelegate {
...
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
...
return Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
...
Text(
'菜品展示',
style: Theme.of(context).textTheme.titleMedium,
),
Expanded(
child: Stack(
children: [
//控制层叠关系
if (percent > uploadlimit) ...[
card,
bottomsliverbar
] else ...[
bottomsliverbar,
card
]
],
),
),
],
),
);
}
@override
double get maxExtent => maxExtended;
@override
double get minExtent => minExtended;
@override
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) =>
false;
}
回转叠加动画经过Stack
结合Transform
完成
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
//shrinkOffset为SliverPersistentHeader翻滚偏移量,用于对应图片的偏移程度
final percent = shrinkOffset / 180;
//约束图片偏移的触发范围
final uploadlimit = 13 / 120;
//运用clamp约束范围
final valueback = (1 - percent - 0.77).clamp(0, uploadlimit);
//将percent的值取平方,用于菜品展示图片下方布景块的位置偏移
final fixrotation = pow(percent, 1.5);
//布景
final bottomsliverbar = _CustomBottomSliverBar(
size: size, fixrotation: fixrotation, percent: percent);
//菜品图片
final card = _CoverCard(
valueback: valueback,
size: size,
percent: percent,
uploadlimit: uploadlimit);
return Container(
...
);
}
图片变换的布局
运用 Matrix4.identity()..rotateZ(...)
完成绕 Z 轴的旋转变换。
Positioned(
top: size.height * 0.005,
left: size.width / 24,
child: Transform(
alignment: Alignment.topRight,
transform: Matrix4.identity()
..rotateZ(percent > uploadlimit
? (valueback * angleForCard)
: percent * angleForCard),
child: CoverPhoto(size: size),
))
//CoverPhoto
Container(
...
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
image: DecorationImage(
...
fit: BoxFit.cover,
)),
)
图片不规则布景+修复动画
布景块经过CustomPainter
进行制作
@override
void paint(Canvas canvas, Size size) {
final paint = Paint();
paint.color = backgroundcolor;
paint.style = PaintingStyle.fill;
paint.strokeWidth = 10;
final path = Path();
path.moveTo(0, size.height);
path.lineTo(size.width, size.height);
path.lineTo(size.width, 0);
path.lineTo(size.width * 0.27, 0);
canvas.drawPath(path, paint);
}
修复动画经过Positioned
的left
做出视觉上的一个视差
Positioned(
right: 0,
bottom: 0,
left: -size.width * fixrotation.clamp(0, 0.35),
child: Container(
height: size.height * 0.12,
child: Stack(
fit: StackFit.expand,
children: [
CustomPaint(
painter: CutRectangle(),
)
],
),
))
剩下部分
剩下部分都是经过SliverToBoxAdapter
来进行完成,详细布局的内容不是本文的要点,就不过多论述了,详见源代码。
总结
至此,三篇组件分化文章+一篇归纳实战文章,我们学习了Sliver
的运用和特性,信任您现已进入了Sliver
的世界。我所写的也只是它魅力的冰山一角
,Sliver
系列组件是用于创建灵敏
的翻滚界面和杂乱
布局的要害,那么请继续探索Sliver的世界,利用其强壮的特性和灵敏的组合方式,创建出更加有趣和具有交互性的翻滚界面吧~(后续还会有更多的运用教程、源码分化…)
关于我
Hello,我是Taxze,如果您觉得文章对您有价值,期望您能给我的文章点个❤️,有问题需求联系我的话:我在这里,也可以经过的新的私信功能联系到我。如果您觉得文章还差了那么点东西,也请经过关注督促我写出更好的文章~如果哪天我前进了呢?