如何在 Flutter 中创建这样的自定义可滑动标签栏?
How can I create a custom swipable tab bar like this in Flutter?
我想创建一个像上面那样的标签栏,它可以用动画滑动。我尝试使用 Flutter 中的默认 Tab 栏小部件来执行此操作,但失败了。我怎样才能让这个标签栏可以用动画滑动?
将所选标签动画从“朋友”标签下移到“家庭”标签背后的逻辑是什么?
我想出了 GestureDetector
小部件中的 onHorizontalDrag
属性 来进行滑动,但仍然无法用动画切换标签。
如果有人能帮助我,那就太好了。
这是使用 PageView
和 customAppBar 制作的。但是,如果你想在 tabBaritem 上使用 clickEvent,请用 GestureDetector
包装,使 callBack
或 stateManagement
保持索引。
结果
MainWidget
class BU extends StatefulWidget {
BU({Key? key}) : super(key: key);
@override
_BUState createState() => _BUState();
}
class _BUState extends State<BU> {
int _selectedIndex = 0;
final PageController controller = PageController(initialPage: 0);
@override
void initState() {
super.initState();
widgets = [
...List.generate(
5,
(index) => Container(
alignment: Alignment.center,
color: index.isEven ? Colors.cyanAccent : Colors.deepPurple,
child: Text(
"Item $index",
style: TextStyle(fontSize: 44),
),
),
)
];
controller.addListener(() {
if (controller.hasClients) {
setState(() {
/// you can ceil foor
_selectedIndex = controller.page!.toInt();
});
}
});
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
late List<Widget> widgets;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
AppBar(
selectedItem: _selectedIndex,
),
Expanded(
child: Container(
width: double.infinity,
child: PageView(
controller: controller,
children: [...widgets],
)),
)
],
),
);
}
}
标签栏
class AppBar extends StatelessWidget {
final int selectedItem;
const AppBar({
Key? key,
required this.selectedItem,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(8),
color: Colors.white,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
TabItemChip(
isSelected: selectedItem == 0,
text: "Profile",
),
TabItemChip(
isSelected: selectedItem == 1,
text: "About",
),
TabItemChip(
isSelected: selectedItem == 2,
text: "Friends",
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
TabItemChip(
isSelected: selectedItem == 3,
text: "Family",
),
TabItemChip(
isSelected: selectedItem == 4,
text: "Settings",
),
],
)
],
),
);
}
}
TabBarItemChip
class TabItemChip extends StatelessWidget {
final bool isSelected;
final String text;
const TabItemChip({
Key? key,
required this.text,
required this.isSelected,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: Duration(milliseconds: 400),
height: 40,
width: 140,
alignment: Alignment.center,
decoration: BoxDecoration(
color: isSelected ? Colors.cyanAccent.shade700 : Colors.white,
borderRadius: BorderRadius.circular(12),
),
child: Text(
text,
style: TextStyle(
color: isSelected ? Colors.white : Colors.black,
fontWeight: FontWeight.bold,
),
),
);
}
}
我想创建一个像上面那样的标签栏,它可以用动画滑动。我尝试使用 Flutter 中的默认 Tab 栏小部件来执行此操作,但失败了。我怎样才能让这个标签栏可以用动画滑动?
将所选标签动画从“朋友”标签下移到“家庭”标签背后的逻辑是什么?
我想出了 GestureDetector
小部件中的 onHorizontalDrag
属性 来进行滑动,但仍然无法用动画切换标签。
如果有人能帮助我,那就太好了。
这是使用 PageView
和 customAppBar 制作的。但是,如果你想在 tabBaritem 上使用 clickEvent,请用 GestureDetector
包装,使 callBack
或 stateManagement
保持索引。
结果
MainWidget
class BU extends StatefulWidget {
BU({Key? key}) : super(key: key);
@override
_BUState createState() => _BUState();
}
class _BUState extends State<BU> {
int _selectedIndex = 0;
final PageController controller = PageController(initialPage: 0);
@override
void initState() {
super.initState();
widgets = [
...List.generate(
5,
(index) => Container(
alignment: Alignment.center,
color: index.isEven ? Colors.cyanAccent : Colors.deepPurple,
child: Text(
"Item $index",
style: TextStyle(fontSize: 44),
),
),
)
];
controller.addListener(() {
if (controller.hasClients) {
setState(() {
/// you can ceil foor
_selectedIndex = controller.page!.toInt();
});
}
});
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
late List<Widget> widgets;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
AppBar(
selectedItem: _selectedIndex,
),
Expanded(
child: Container(
width: double.infinity,
child: PageView(
controller: controller,
children: [...widgets],
)),
)
],
),
);
}
}
标签栏
class AppBar extends StatelessWidget {
final int selectedItem;
const AppBar({
Key? key,
required this.selectedItem,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(8),
color: Colors.white,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
TabItemChip(
isSelected: selectedItem == 0,
text: "Profile",
),
TabItemChip(
isSelected: selectedItem == 1,
text: "About",
),
TabItemChip(
isSelected: selectedItem == 2,
text: "Friends",
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
TabItemChip(
isSelected: selectedItem == 3,
text: "Family",
),
TabItemChip(
isSelected: selectedItem == 4,
text: "Settings",
),
],
)
],
),
);
}
}
TabBarItemChip
class TabItemChip extends StatelessWidget {
final bool isSelected;
final String text;
const TabItemChip({
Key? key,
required this.text,
required this.isSelected,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: Duration(milliseconds: 400),
height: 40,
width: 140,
alignment: Alignment.center,
decoration: BoxDecoration(
color: isSelected ? Colors.cyanAccent.shade700 : Colors.white,
borderRadius: BorderRadius.circular(12),
),
child: Text(
text,
style: TextStyle(
color: isSelected ? Colors.white : Colors.black,
fontWeight: FontWeight.bold,
),
),
);
}
}