You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

187 lines
5.1 KiB

import 'package:flutter/material.dart';
typedef TabBarItemBuilder<T> = Widget Function(
BuildContext context, int index, T item);
typedef TabBarItemClickListener = Function(int index);
class SCTabBar<T> extends StatefulWidget {
SCTabBar({
required this.items,
required this.itemBuilder,
this.direction = Axis.horizontal,
this.height = 30,
this.spacing = 0,
this.padding = const EdgeInsets.all(0),
this.indicatorHeight = 2,
this.indicatorColor = Colors.red,
this.indicatorLocation = IndicatorLocation.bottom,
this.initialIndex = 0,
this.itemClick,
required this.controller,
}) : assert(items.length != 0, "item个数不能为空");
final TabBarController controller;
final Axis direction;
final double height;
final double spacing;
final EdgeInsetsGeometry padding;
final IndicatorLocation indicatorLocation;
final double indicatorHeight;
final Color indicatorColor;
final List<T> items;
final TabBarItemBuilder<T> itemBuilder;
final initialIndex;
final TabBarItemClickListener? itemClick;
@override
State<StatefulWidget> createState() {
return _SCTabBarState<T>(itemBuilder);
}
}
class _SCTabBarState<T> extends State<SCTabBar> {
final TabBarItemBuilder<T> itemBuilder;
_SCTabBarState(this.itemBuilder);
int? _selectedIndex;
@override
void initState() {
super.initState();
_selectedIndex = widget.initialIndex;
widget.controller.jumpToIndex = (int index) {
print(index);
setState(() {
_selectedIndex = index;
});
};
}
@override
Widget build(BuildContext context) {
return Container(
padding: widget.padding,
decoration: BoxDecoration(
border:
Border(right: BorderSide(color: Colors.green[300]!, width: 0.1))),
child: ListView.builder(
itemCount: widget.items.length,
scrollDirection: widget.direction,
itemBuilder: (context, index) {
return GestureDetector(
child: Container(
color: Color(0xFFF2F2F2),
padding: _itemSpaceEdge(),
child: Container(
height: widget.height,
child: Stack(
children: [
itemBuilder(context, index, widget.items[index]),
Positioned(
left: 0,
top: 0,
bottom: 0,
child: _indicatorBorder(index),
),
],
),
),
),
onTap: () {
if (widget.itemClick != null) {
widget.itemClick!(index);
}
setState(() {
_selectedIndex = index;
});
},
);
},
),
);
}
EdgeInsetsGeometry _itemSpaceEdge() {
if (widget.direction == Axis.horizontal) {
return EdgeInsets.only(
left: widget.spacing / 2,
right: widget.spacing / 2,
);
} else {
return EdgeInsets.only(
top: widget.spacing / 2,
bottom: widget.spacing / 2,
);
}
}
Widget _indicatorBorder(index) {
if (index != _selectedIndex) {
return Container();
}
Widget border;
switch (widget.indicatorLocation) {
case IndicatorLocation.top:
border = Container(
height: widget.indicatorHeight,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(1), topRight: Radius.circular(5)),
color: widget.indicatorColor),
);
break;
case IndicatorLocation.left:
border = Container(
width: widget.indicatorHeight,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(widget.indicatorHeight / 2),
topRight: Radius.circular(widget.indicatorHeight / 2)),
color: widget.indicatorColor,
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: <Color>[
Color(0xFFD5101A),
Color(0xFFFFFFFF),
],
),
),
);
break;
case IndicatorLocation.right:
border = Container(
width: widget.indicatorHeight,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topRight: Radius.circular(widget.indicatorHeight / 2),
bottomRight: Radius.circular(widget.indicatorHeight / 2)),
color: widget.indicatorColor),
);
break;
default:
border = Container(
height: widget.indicatorHeight,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(5),
bottomLeft: Radius.circular(5)),
color: widget.indicatorColor),
);
}
return border;
}
}
enum IndicatorLocation { top, bottom, left, right }
class TabBarController {
late Function(int index) jumpToIndex;
}