【Flutter小记】使用SliverPersistentHeader实现吸顶效果案例效果展示 首先头部是一个悬浮Sli
案例效果展示
首先头部是一个悬浮SliverPersistentHeader,在任意位置下滑该组件都会出现,上滑就会消失,一般在该区域会放置搜索框等组件,第二个可伸缩区域也是一个SliverPersistentHeader,可以在该部分做一些布局的改变和动画。

代码部分
整体布局比较简单,由CustomScrollView包裹,两个Box和一个SliverList组成。
return CustomScrollView(
slivers: [
_buildFloatBox(),
_buildStickBox(),
_buildSliverList()
],
);
先看_buildFloatBox,它的floating属性设置为true。FloatingSPHD继承SliverPersistentHeaderDelegate,build方法提供的shrinkOffset属性和maxExtent和minExtent下面会讲到,重点在于复写showOnScreenConfiguration计算属性。
Widget _buildFloatBox() {
return SliverPersistentHeader(
floating: true,
delegate: FloatingSPHD(height: 54),
);
}
class FloatingSPHD extends SliverPersistentHeaderDelegate {
final double height;
FloatingSPHD({required this.height});
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return Container(
height: height,
alignment: Alignment.center,
color: Colors.green,
child: const Text(
"悬浮Header",
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
);
}
@override
double get maxExtent => height;
@override
double get minExtent => height;
@override
bool shouldRebuild(covariant FloatingSPHD oldDelegate) {
return oldDelegate.height != height;
}
@override
PersistentHeaderShowOnScreenConfiguration get showOnScreenConfiguration =>
const PersistentHeaderShowOnScreenConfiguration(
minShowOnScreenExtent: double.infinity);
}
可伸缩区域也是由单个SliverPersistentHeader构成(以下简称SPH),pinned属性设置为true可以在SPH向上移动到页面顶部时固定,而不是滑出边界。FlexibleSPHD的build方法内,通过shrinkOffset属性控制了SizedBox的高度和opacity属性,使需要隐藏部分在上滑的过程中可以自然的消失。shrinkOffset是SPH高度的偏移量,例如当设置最大高度为80,最小高度为40,在上滑的过程中,SPH的高度由80逐渐缩小至40。shrinkOffset属性值由0逐渐增至40,所以在使用时需要对它进行变换。
overlapsContent属性在源码中有这样的描述:如果后续有slivers将呈现在此组件下面,则为真,否则为假,通常,这用于决定是否绘制阴影以模拟sliver位于其下方内容上方。当shrinkOffset处于最大值时,为真,否则为假,但这并不能保证。请参阅 [NestedScrollView],了解overlapsContent的值可能与shrinkOffset无关的情况示例。总的来说该属性用处不大。
Widget _buildStickBox() {
return SliverPersistentHeader(
pinned: true, delegate: FlexibleSPHD(min: 40, max: 80));
}
class FlexibleSPHD extends SliverPersistentHeaderDelegate {
final double max;
final double min;
FlexibleSPHD({required this.max, required this.min});
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
double progress = shrinkOffset / (max - min);
progress = progress > 1 ? 1 : progress;
return Container(
color: Color.lerp(Colors.blue, Colors.red, progress),
child: Column(children: [
const Text(
"可伸缩区域",
style: TextStyle(
color: Colors.white, fontSize: 16, fontWeight: FontWeight.bold),
),
SizedBox(height: (1 - progress) * 20),
Opacity(
opacity: 1 - progress,
child: SizedBox(
height: (1 - progress) * 30,
child: const Text("需要隐藏部分",
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold)),
),
)
]),
);
}
@override
double get maxExtent => max;
@override
double get minExtent => min;
@override
bool shouldRebuild(covariant FlexibleSPHD oldDelegate) {
return oldDelegate.min != min || oldDelegate.max != max;
}
}
祝编程愉快
转载自:https://juejin.cn/post/7371821661237346340