携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第7天,点击查看活动详情
前言
在Flutter开发过程中经常会遇到导航栏吸顶的需求,我们可以使用Sliver系列组件实现吸顶导航栏功能。本文探讨的主题就是使用SliverPersistentHeader组件实现导航栏吸顶功能。
SliverPersistentHeader组件简介
SliverPersistentHeader是一个滚动到视窗边缘时大小会发生变化的组件,主要包含delegate、pinned和floating三个参数:
const SliverPersistentHeader({
Key? key,
required this.delegate,
this.pinned = false,
this.floating = false,
}) : assert(delegate != null),
assert(pinned != null),
assert(floating != null),
super(key: key);
1. delegate
delegate参数需要重新实现SliverPersistentHeaderDelegate方法,并对build、minExtent、maxExtent、shouldRebuild四种方法进行复写:
build:放置在SliverPersistentHeader内的小部件;
minExtent:允许组件达到的最小尺寸;
maxExtent:允许组件达到的最大尺寸,也是组件在顶部未缩小时的尺寸。
shouldRebuild:当oldDelegate对象返回的数据改变时,是否重新构建SliverPersistentHeader组件。
2. pinned
pinned参数表示当组件达到其最小高度 (即滑动到顶部) 时是否固定在顶部不动,当pinned值为true时表示滑动到顶部后固定不动,pinned值为false则表示滑动到顶部后直接滑出页面。pinned参数值默认为false;
3. floating
floating参数表示用户反转滚动方向 (即向上滑动) ,组件是否立即恢复最大高度,当floating值为true时表示立即恢复最大高度,floating值为false则表示滑动到顶部时恢复最大高度。floating参数值默认为false。
功能代码
可以在实现SliverPersistentHeaderDelegate方法时对该方法进行封装,通过传入参数实现导航栏吸顶的功能,完整代码如下:
import 'package:flutter/material.dart';
class SliverDemo extends StatefulWidget {
const SliverDemo({Key? key}) : super(key: key);
@override
State<SliverDemo> createState() => _SliverDemoState();
}
class _SliverDemoState extends State<SliverDemo> with SingleTickerProviderStateMixin {
final List _tab = ['第一', '第二', '第三', '第四'];
late TabController _tabController;
@override
void initState() {
// TODO: implement initState
super.initState();
_tabController = TabController(length: _tab.length, vsync: this);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: CustomScrollView(
slivers: [
SliverPersistentHeader(
delegate: SliverTabBar(
tabController: _tabController,
tab: _tab,
isScrollable: false,
minHeight: 40,
maxHeight: 50,
onTap: (i) {
print(i);
},
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(8),
topRight: Radius.circular(8),
),
backgroundColor: const Color(0xFFF6F6F6),
tabColor: const Color(0xFFF6F6F6),
),
pinned: true,
floating: true,
),
],
),
);
}
}
// 实现SliverPersistentHeaderDelegate方法
class SliverTabBar extends SliverPersistentHeaderDelegate {
TabController tabController; //必传参数,控制器
List tab; //必传参数,导航项列表
double maxHeight; //导航栏最大高度
double minHeight; //导航栏最小高度
bool isScrollable; //是否可以滚动,默认false
Function(int)? onTap; //点击导航项事件
BorderRadiusGeometry? borderRadius; //导航栏圆角
Color? backgroundColor; //背景颜色
Color? tabColor; //导航栏颜色
SliverTabBar({
required this.tabController,
required this.tab,
this.isScrollable = false,
this.maxHeight = 44,
this.minHeight = 44,
this.onTap,
this.borderRadius,
this.backgroundColor,
this.tabColor,
});
@override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
return Container(
color: tabColor ?? const Color(0xFFF6F6F6),
child: Container(
height: maxHeight,
decoration: BoxDecoration(
color: backgroundColor ?? const Color(0xFFF6F6F6),
borderRadius: borderRadius ?? BorderRadius.zero,
),
child: TabBar(
isScrollable: isScrollable,
onTap: onTap,
labelStyle: const TextStyle(color: Color(0xFFFF6720), fontSize: 14),
labelColor: const Color(0xFFFF6720),
indicatorColor: const Color(0xFFFF6720),
indicatorSize: TabBarIndicatorSize.label,
unselectedLabelColor: const Color(0xFF76777B),
unselectedLabelStyle: const TextStyle(color: Color(0xFF76777B), fontSize: 14),
controller: tabController,
tabs: tab.map((e) => Tab(child: Text(e))).toList(),
),
),
);
}
@override
// TODO: implement maxExtent
double get maxExtent => maxHeight;
@override
// TODO: implement minExtent
double get minExtent => minHeight;
@override
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
return false;
}
}
效果图如下:
总结
Sliver家族有着许多强大的功能组件,本文讲述了SliverPersistentHeader组件实现导航栏吸顶的功能。