TAB是在不同应用程序框架中广泛使用的接口布局,Flutter也不例外。Flutter提供了一种方便快捷的方法来使用Material库创建TAB布局。
一般来说在Flutter中创建TAB布局,需要实现以下步骤:
- 创建一个TabController。
- 创建一个TabBar。
- 创建一个TabBarView。
1. TabController
要使TAB布局正常工作,需要将所选Tab与它的内容同步,这是TabController
的工作。
可以手动创建TabController
,或者使用可用的Widget(称为DefaultTabController
)来支持一些常用功能。
DefaultTabController(
// The number of tabs / content sections to display.
length: 3,
child: // Complete this code in the next step.
);
2. 标签栏
TabBar
可帮助我们创建Tab,如以下示例所示,TabBar包含三个子Tab。
TabBar示例代码:
DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
tabs: [
Tab(icon: Icon(Icons.directions_car)),
Tab(icon: Icon(Icons.directions_transit)),
Tab(icon: Icon(Icons.directions_bike)),
],
),
),
),
);
注意:可以将许多
TabBar
放入DefaultTabController
中,但是DefaultTabController
仅适用于最近的TabBar(按树结构搜索)。在这种情况下,需要考虑手动创建自己的TabController
。
3. TabBarView
可以使用TabBarView
包含与TabBar
上每个Tab相对应的内容。
TabBarView (
children: [
Icon(Icons.directions_car),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
],
);
4. TabBar示例
文件:main.dart
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Title of Application',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
tabs: [
Tab(icon: Icon(Icons.directions_car)),
Tab(icon: Icon(Icons.directions_transit)),
Tab(icon: Icon(Icons.directions_bike)),
],
),
title: Text('Flutter Tabs Example'),
),
body: TabBarView(
children: [
Center(child: Text("Car")),
Center(child: Text("Transit")),
Center(child: Text("Bike"))
],
),
)
);
}
}
运行上面示例代码,得到以下结果:
5. TabController, TabBar构造器
5.1. TabController构造器
TabController(
{int initialIndex: 0,
@required int length,
@required TickerProvider vsync}
)
DefaultTabController 构造函数:
const DefaultTabController(
{Key key,
@required int length,
int initialIndex: 0,
@required Widget child}
)
TabBar 构造函数:
const TabBar(
{Key key,
@required List<Widget> tabs,
TabController controller,
bool isScrollable: false,
Color indicatorColor,
double indicatorWeight: 2.0,
EdgeInsetsGeometry indicatorPadding: EdgeInsets.zero,
Decoration indicator,
TabBarIndicatorSize indicatorSize,
Color labelColor,
TextStyle labelStyle,
EdgeInsetsGeometry labelPadding,
Color unselectedLabelColor,
TextStyle unselectedLabelStyle,
DragStartBehavior dragStartBehavior: DragStartBehavior.start,
MouseCursor mouseCursor,
ValueChanged<int> onTap,
ScrollPhysics physics}
)
TabBarView 构造函数:
const TabBarView(
{Key key,
@required List<Widget> children,
TabController controller,
ScrollPhysics physics,
DragStartBehavior dragStartBehavior: DragStartBehavior.start}
)
6. isScrollable
示例文件:main.dart
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Title of Application',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
EdgeInsets a2; EdgeInsetsDirectional a;
return DefaultTabController(
length: 6,
child: Scaffold(
appBar: AppBar(
bottom: createTabBar(),
title: Text('Flutter TabBar Example'),
),
body: TabBarView(
children: [
Center(child: Text("Car")),
Center(child: Text("Transit")),
Center(child: Text("Bike")),
Center(child: Text("Boat")),
Center(child: Text("Railway")),
Center(child: Text("Bus"))
],
),
)
);
}
TabBar createTabBar() {
return TabBar(
tabs: [
Row (children: [Icon(Icons.directions_car), SizedBox(width:5), Text("Car")]),
Row (children: [Icon(Icons.directions_transit), SizedBox(width:5), Text("Transit")]),
Row (children: [Icon(Icons.directions_bike), SizedBox(width:5), Text("Bike")]),
Row (children: [Icon(Icons.directions_boat), SizedBox(width:5), Text("Boat")]),
Row (children: [Icon(Icons.directions_railway), SizedBox(width:5), Text("Railway")]),
Row (children: [Icon(Icons.directions_bus), SizedBox(width:5), Text("Bus")]),
],
isScrollable: true,
);
}
}
例如,在TabBar.isScrollable = true
的情况下,向左对齐Tab。示例代码:main.dart
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Title of Application',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
EdgeInsets a2; EdgeInsetsDirectional a;
return DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
bottom: PreferredSize(
preferredSize: Size.fromHeight(40),
child: Align(
alignment: Alignment.centerLeft,
child: TabBar(
isScrollable: true,
tabs: [ Row (children: [Icon(Icons.directions_car), SizedBox(width:5), Text("Car")]),
Row (children: [Icon(Icons.directions_transit), SizedBox(width:5), Text("Transit")]),
Row (children: [Icon(Icons.directions_bike), SizedBox(width:5), Text("Bike")])],
),
),
),
title: Text('Flutter TabBar Example'),
),
body: TabBarView(
children: [
Center(child: Text("Car")),
Center(child: Text("Transit")),
Center(child: Text("Bike"))
],
),
)
);
}
}
7. indicatorColor
indicatorColor
属性使您可以指定当前选定选项卡下线的颜色。如果指定了indicator
属性,则将忽略此属性。
Color indicatorColor
例如:在当前选定的选项卡下,为该行设置红色:
TabBar (
tabs: [
Row (children: [Icon(Icons.directions_car), SizedBox(width:5), Text("Car")]),
Row (children: [Icon(Icons.directions_transit), SizedBox(width:5), Text("Transit")]),
Row (children: [Icon(Icons.directions_bike), SizedBox(width:5), Text("Bike")]),
],
indicatorColor: Color(0xffE74C3C),
);
8. indicatorWeight
indicatorWeight
属性用于设置当前选定选项卡下线的粗细。它的值大于0
,默认值为2
。如果指定了indicator
属性,则将忽略此属性。
double indicatorWeight;
例如,在当前选定的选项卡下设置线条的粗细。
indicatorWeight
示例
TabBar(
tabs: [
Row (children: [Icon(Icons.directions_car), SizedBox(width:5), Text("Car")]),
Row (children: [Icon(Icons.directions_transit), SizedBox(width:5), Text("Transit")]),
Row (children: [Icon(Icons.directions_bike), SizedBox(width:5), Text("Bike")]),
],
indicatorColor: Color(0xffE74C3C),
indicatorWeight: 10
);
9. indicatorPadding
indicatorPadding
属性为当前选定的选项卡下的行指定水平填充。
EdgeInsetsGeometry indicatorPadding
indicatorPadding
示例
TabBar(
tabs: [
Row (children: [Icon(Icons.directions_car), SizedBox(width:5), Text("Car")]),
Row (children: [Icon(Icons.directions_transit), SizedBox(width:5), Text("Transit")]),
Row (children: [Icon(Icons.directions_bike), SizedBox(width:5), Text("Bike")]),
],
indicatorColor: Color(0xffE74C3C),
indicatorWeight: 10,
indicatorPadding: EdgeInsets.only(right: 20),
);
10. indicator
indicator
属性定义当前选定选项卡的外观。如果使用此属性,则其他属性(如indicatorColor
,indicatorWeight
和indicatorPadding
)将被忽略。
Decoration indicator;
TabBar(
tabs: [
Row (children: [Icon(Icons.directions_car), SizedBox(width:5), Text("Car")]),
Row (children: [Icon(Icons.directions_transit), SizedBox(width:5), Text("Transit")]),
Row (children: [Icon(Icons.directions_bike), SizedBox(width:5), Text("Bike")]),
],
indicator: ShapeDecoration (
shape: UnderlineInputBorder (
borderSide: BorderSide(
color: Colors.transparent,
width: 0,
style: BorderStyle.solid
)
),
gradient: LinearGradient(colors: [Color(0xff0081ff), Color(0xff01ff80)])
)
);
11. labelColor
labelColor
属性用于为当前所选Tab的标签指定字体颜色。
Color labelColor;
示例:
TabBar(
tabs: [
Row (children: [Icon(Icons.directions_car), SizedBox(width:5), Text("Car")]),
Row (children: [Icon(Icons.directions_transit), SizedBox(width:5), Text("Transit")]),
Row (children: [Icon(Icons.directions_bike), SizedBox(width:5), Text("Bike")]),
],
labelColor: Colors.red,
unselectedLabelColor: Colors.black,
);
12. unselectedLabelColor
unselectedLabelColor
属性用于为未选中的选项卡的Tab
指定字体颜色。
Color unselectedLabelColor;
示例:unselectedLabelColor
TabBar(
tabs: [
Row (children: [Icon(Icons.directions_car), SizedBox(width:5), Text("Car")]),
Row (children: [Icon(Icons.directions_transit), SizedBox(width:5), Text("Transit")]),
Row (children: [Icon(Icons.directions_bike), SizedBox(width:5), Text("Bike")]),
],
labelColor: Colors.white,
unselectedLabelColor: Colors.cyanAccent,
);
13. labelPadding
labelPadding
属性用于向Tab的每个标签添加填充。
EdgeInsetsGeometry labelPadding;
示例:
TabBar(
tabs: [
Row (children: [Icon(Icons.directions_car), SizedBox(width:5), Text("Car")]),
Row (children: [Icon(Icons.directions_transit), SizedBox(width:5), Text("Transit")]),
Row (children: [Icon(Icons.directions_bike), SizedBox(width:5), Text("Bike")]),
],
labelPadding: EdgeInsets.all( 20),
);
13. labelStyle
labelStyle
属性用于在当前选定的选项卡的标签上指定文本样式。
TextStyle labelStyle;
示例代码
TabBar(
tabs: [
Row (children: [Icon(Icons.directions_car), SizedBox(width:5), Text("Car")]),
Row (children: [Icon(Icons.directions_transit), SizedBox(width:5), Text("Transit")]),
Row (children: [Icon(Icons.directions_bike), SizedBox(width:5), Text("Bike")]),
],
labelStyle: TextStyle(fontWeight: FontWeight.bold, fontSize: 22),
unselectedLabelStyle: TextStyle(fontStyle: FontStyle.normal, fontSize: 18),
);
14. unselectedLabelStyle
unselectedLabelStyle
属性用于在未选中的选项卡的标签上指定文本样式。
TextStyle unselectedLabelStyle;
示例:
示例代码:
TabBar(
tabs: [
Row (children: [Icon(Icons.directions_car), SizedBox(width:5), Text("Car")]),
Row (children: [Icon(Icons.directions_transit), SizedBox(width:5), Text("Transit")]),
Row (children: [Icon(Icons.directions_bike), SizedBox(width:5), Text("Bike")]),
],
labelStyle: TextStyle(fontWeight: FontWeight.bold, fontSize: 22),
unselectedLabelStyle: TextStyle(fontStyle: FontStyle.italic),
);
15. onTap
onTap是一种回调函数,当用户点击TabBar上的一个Tab时调用。
ValueChanged<int> onTap;
示例:
示例代码:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Title of Application',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return MyHomePageState();
}
}
class MyHomePageState extends State<MyHomePage> {
int carClick = 0;
int transitClick = 0;
int bikeClick = 0;
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
bottom: createTabBar(),
title: Text('Flutter TabBar Example'),
),
body: TabBarView(
children: [
Center(child: Text("Car")),
Center(child: Text("Transit")),
Center(child: Text("Bike"))
],
),
)
);
}
TabBar createTabBar() {
return TabBar(
isScrollable: true,
labelStyle: TextStyle(fontSize: 20),
tabs: [
Text("Car " + this.carClick.toString()),
Text("Transit " + this.transitClick.toString()),
Text("Bike " + this.bikeClick.toString())
],
onTap: (index) {
this.onTapHandler(index);
}
);
}
void onTapHandler(int index) {
setState(() {
switch(index){
case 0:
carClick++;
break;
case 1:
transitClick++;
break;
case 2:
bikeClick++;
break;
}
});
}
}