先看效果
实现代码
class OptionsTab extends StatefulWidget {
const OptionsTab({
Key key,
}) : super(key: key);
@override
_OptionsTabState createState() => _OptionsTabState();
}
class _OptionsTabState extends State<OptionsTab> {
ScrollController scrollController;
List optionList;
int _currentSelectedIndex = 0;
@override
void initState() {
optionList = [
'全部',
'通知',
'作业',
'打卡',
'通知',
'作业',
'打卡',
'通知',
'作业',
'打卡',
'通知',
'作业',
'打卡',
];
scrollController = ScrollController();
super.initState();
}
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(vertical: 5),
height: 30,
color: Colors.white,
child: ListView.builder(
scrollDirection: Axis.horizontal,
controller: scrollController,
itemBuilder: (BuildContext context, int index) {
bool selected = _currentSelectedIndex == index;
return GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
if (_currentSelectedIndex == index) {
return;
}
ScrollPosition position = scrollController.position;
print(
'position index:$index viewportDimension:${position.viewportDimension} minScrollExtent:${position.minScrollExtent} maxScrollExtent${position.maxScrollExtent}');
/// 计算当前选中的 Tab 的 offset
double currentOffset = 50 * index.toDouble();
/// 计算居中的 offset
double centerOffset = currentOffset + 25;
/// 计算最终滚动的 offset 距离
double absOffset = (centerOffset - position.viewportDimension / 2)
.clamp(position.minScrollExtent, position.maxScrollExtent)
.toDouble();
print(
'currentOffset:$currentOffset centerOffset:$centerOffset absOffset:$absOffset');
/// 通过 controller 滚动到对于的距离
scrollController.animateTo(absOffset,
duration: kTabScrollDuration, curve: Curves.ease);
_currentSelectedIndex = index;
setState(() {});
},
child: Container(
margin: EdgeInsets.symmetric(horizontal: 5),
decoration: BoxDecoration(
color: selected ? Colors.white : Colors.grey[200],
border: Border.all(
color: selected ? Colors.blue : Colors.grey[300],
),
borderRadius: BorderRadius.circular(4)),
child: Text(
'${optionList[index]}',
style: TextStyle(
color: selected ? Colors.blue : Colors.grey[500],
fontSize: 10,
),
),
alignment: Alignment.center,
height: 30,
width: 50,
),
);
},
itemCount: optionList?.length ?? 0,
),
);
}
}
使用上面的小算法就可以实现 listview 滚动到对应的 item
ScrollPosition position = scrollController.position;
print(
'position index:$index viewportDimension:${position.viewportDimension} minScrollExtent:${position.minScrollExtent} maxScrollExtent${position.maxScrollExtent}');
/// 计算当前选中的 Tab 的 offset
double currentOffset = 50 * index.toDouble();
/// 计算居中的 offset
double centerOffset = currentOffset + 25;
/// 计算最终滚动的 offset 距离
double absOffset = (centerOffset - position.viewportDimension / 2)
.clamp(position.minScrollExtent, position.maxScrollExtent)
.toDouble();
print(
'currentOffset:$currentOffset centerOffset:$centerOffset absOffset:$absOffset');
/// 通过 controller 滚动到对于的距离
scrollController.animateTo(absOffset,
duration: kTabScrollDuration, curve: Curves.ease);