0 purchases
view tabbar
ViewTabBar #
ViewTabBar 基于 TabBarController 和 PageController,实现了 TabBar 和 PageView 之间在 UI 上的解耦及联动。
可实现 TabBar + PageView (horizontal)
可实现 TabBar + PageView (vertical)
可实现 Carousel (轮播图)
如何安装 #
在 pubspec.yaml 添加
dependencies:
view_tabbar: ^1.3.0
copied to clipboard
在命令行运行如下
flutter pub get
copied to clipboard
如何使用 #
TabBar + PageView (pinned)
import 'package:flutter/material.dart';
import 'package:view_tabbar/view_tabbar.dart';
class HorizontalWithPinned extends StatelessWidget {
HorizontalWithPinned({super.key});
final pageController = PageController();
final tabBarController = ViewTabBarController();
@override
Widget build(BuildContext context) {
const tags = ['板块1', '板块2', '板块3', '板块4'];
const duration = Duration(milliseconds: 300);
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// ViewTabBar
ViewTabBar(
pinned: true,
itemCount: tags.length,
direction: Axis.horizontal,
pageController: pageController,
tabBarController: tabBarController,
animationDuration: duration, // 取消动画 -> Duration.zero
builder: (context, index) {
return ViewTabBarItem(
index: index,
transform: ScaleTransform(
maxScale: 1.2,
transform: ColorsTransform(
normalColor: const Color(0xff606266),
highlightColor: const Color(0xff436cff),
builder: (context, color) {
return Container(
alignment: Alignment.center,
padding: const EdgeInsets.only(
top: 8.0,
left: 10.0,
right: 10.0,
bottom: 8.0,
),
child: Text(
tags[index],
style: TextStyle(
color: color,
fontWeight: FontWeight.w500,
fontSize: 14.0,
),
),
);
},
),
),
);
},
// StandardIndicator
indicator: StandardIndicator(
color: const Color(0xff436cff),
width: 27.0,
height: 2.0,
bottom: 0,
),
),
// PageView
Expanded(
flex: 1,
child: PageView.builder(
itemCount: tags.length,
controller: pageController,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return Container(
padding: const EdgeInsets.only(
top: 16.0,
left: 16.0,
right: 16.0,
bottom: 16.0,
),
child: Text(
'这里渲染显示 ${tags[index]} 的内容',
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: Color(0xff606266),
),
),
);
},
),
),
],
);
}
}
copied to clipboard
Carousel (轮播图)
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:view_tabbar/view_tabbar.dart';
class CarouselWithTarBar extends StatefulWidget {
const CarouselWithTarBar({super.key});
@override
CarouselWithTarBarState createState() => CarouselWithTarBarState();
}
class CarouselWithTarBarState extends State<CarouselWithTarBar> {
// 共 6 个 Card 轮播元素
// 因需要实现无限轮播的效果
// 需在第一个元素前添加最后一个元素
// 且在最后一个元素前添加第一个元素
// 如此下来则就有共计 8 个轮播元素
// 默认显示第2个轮播元素 (即 6 个 Card 中第一个)
final pageController = PageController(initialPage: 1);
final tabBarController = ViewTabBarController();
int _currentIndex = 1;
Timer? _timer;
// 定时轮播 - 每隔 3s
void _setTimer() {
_timer?.cancel();
_timer = Timer.periodic(const Duration(seconds: 3), (_) {
int page = _currentIndex + 1;
pageController.animateToPage(
page,
duration: const Duration(milliseconds: 400),
curve: Curves.easeOut,
);
});
}
@override
void initState() {
super.initState();
_setTimer();
}
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.only(
top: 10.0,
bottom: 12.0,
),
clipBehavior: Clip.antiAlias,
decoration: ShapeDecoration(
gradient: const LinearGradient(
begin: Alignment(0.00, -1.00),
end: Alignment(0, 1),
stops: [0, 0.2, 1],
colors: [
Color(0xFFEEF3FF),
Color(0xFFEEF3FF),
Colors.white,
],
),
shape: RoundedRectangleBorder(
side: const BorderSide(width: 1.50, color: Colors.white),
borderRadius: BorderRadius.circular(12.0),
),
),
child: Column(
children: [
// 标题
Container(
height: 24.0,
alignment: Alignment.centerLeft,
margin: const EdgeInsets.only(top: 10.0),
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: const Text(
"职业类型",
style: TextStyle(
color: Color(0xFF101828),
fontSize: 18.0,
fontFamily: 'PingFang SC',
fontWeight: FontWeight.w500,
height: 1,
),
),
),
// PageView
Container(
height: 72.0,
margin: const EdgeInsets.only(
top: 16.0,
bottom: 20.0,
),
padding: const EdgeInsets.only(
left: 16.0,
right: 10.0,
),
child: NotificationListener(
onNotification: (notification) {
if (notification is! ScrollNotification ||
notification.depth != 0) {
return false;
}
if (notification is ScrollUpdateNotification) {
// 关闭定时器
_timer?.cancel();
}
if (notification is ScrollStartNotification) {
if (notification.dragDetails != null) {
// 关闭定时器
_timer?.cancel();
}
}
if (notification is ScrollEndNotification) {
final page = pageController.page?.round();
// last, 处理 end 边界
if (page == 7) {
Future.delayed(const Duration(milliseconds: 10), () {
pageController.jumpToPage(1);
_setTimer();
});
return true;
}
// first, 处理 start 边界
if (page == 0) {
Future.delayed(const Duration(milliseconds: 10), () {
pageController.jumpToPage(3);
_setTimer();
});
return true;
}
// 延时启动定时器
Future.delayed(
const Duration(milliseconds: 20),
() {
setState(() {
_currentIndex = page ?? 1;
_setTimer();
});
},
);
}
return true;
},
child: PageView.builder(
itemCount: 8,
controller: pageController,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
// first, 处理 start 边界
if (index == 0) {
index = 6;
}
// last, 处理 end 边界
if (index == 7) {
index = 1;
}
return renderPageViewContent(
context,
index,
);
},
),
),
),
// TarBar
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
flex: 0,
child: ClipRect(
clipper: ViewTabBarClipper(),
child: ViewTabBar(
pinned: true,
height: 14.0,
width: 160.0,
direction: Axis.horizontal,
pageController: pageController,
tabBarController: tabBarController,
animationDuration: const Duration(milliseconds: 300),
indicator: StandardIndicator(
width: 15.0,
height: 4.0,
color: const Color(0xff436cff),
radius: const BorderRadius.all(Radius.circular(3.0)),
bottom: 5,
),
itemCount: 8,
builder: (context, index) {
return ViewTabBarItem(
index: index,
child: Container(
width: 14.0,
height: 4.0,
margin: const EdgeInsets.only(
left: 2.0,
right: 2.0,
),
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(2),
),
color: Color(0x66436cff),
),
),
);
},
),
),
),
],
),
],
),
);
}
}
// 截取 TabBar 容器大小
class ViewTabBarClipper extends CustomClipper<Rect> {
@override
Rect getClip(Size size) {
// 共 8 个 tab item (每个 tab -> 宽度: 20, 高度: 14)
// 截取保留 第 2 - 7 tab 元素 -> Rect.fromLTWH(20, 0, 120, 14)
return const Rect.fromLTWH(20, 0, 120, 14);
}
@override
bool shouldReclip(covariant CustomClipper<Rect> oldClipper) {
return false;
}
}
// 渲染 PageView 内容
Widget renderPageViewContent(context, index) {
// PageView 内容 ....
}
copied to clipboard
API 说明 #
ViewTabBar #
API
说明
必选
默认值
pinned
tabbar 固定
否
false
builder
widget 构建
是
itemCount
tabbar 数量
是
direction
tabbar 方向
否
Axis.horizontal
indicator
tabbar 指示器
否
pageController
PageView controller
是
PageController
tabBarController
ViewTabBar controller
否
ViewTabBarController
animationDuration
动画时长,Duration.zero -> 禁用动画
否
Duration(milliseconds: 300)
controllerToScroll
PageView 滚动时,联动 TabBar/Indicator
否
true
controllerToJump
TabBar 滑动时,联动 PageView 滚动
否
true
onTapItem
TabBar Item onTap 事件
否
height
tabbar 高度,当 direction 为 Axis.horizontal 时,请指定值
否
width
tabbar 宽度,当 direction 为 Axis.vertical 时,请指定值
否
ViewTabBarItem #
API
说明
必选
默认值
index
tabar item index
是
child
tabar item child
否
transform
tabar item transform, 目前有 ColorsTransform / ScaleTransform
否
StandardIndicator #
API
说明
必选
默认值
top
indicator 顶部
否
left
indicator 左侧
否
right
indicator 右侧
否
bottom
indicator 底部
否
width
indicator 宽度
否
height
indicator 高度
否
radius
indicator border radius
否
color
indicator color
否
ColorsTransform #
API
说明
必选
默认值
builder
widget 构建
否
transform
transformer,嵌套使用 ScaleTransform
否
normalColor
tabbar 正常颜色
否
highlightColor
tabbar 高亮颜色
否
ScaleTransform #
API
说明
必选
默认值
builder
widget 构建
否
transform
transformer,嵌套使用 ColorsTransform
否
maxScale
tabbar 最大可缩放值
否
1.2
Gif 演示 #
TabBar + PageView ------ (horizontal) 看源码 #
TabBar + PageView ------ (vertical) 看源码 #
Carousel ------ (轮播图) 看源码 #
For personal and professional use. You cannot resell or redistribute these repositories in their original state.
There are no reviews.