TAB là một bố cục giao diện nằm trong đối tượng TabBar, TabBar chứa nhiều Tab và thường được dùng để phân loại các Widget có cùng tính chất với nhau vào cùng một Tab
Tab được sử dụng gắn liền với TabController, TabBar, TabBarView
TabController
TabController có nhiệm vụ đồng bộ hóa các TAB trong suốt quá trình hoạt động, TabController có thể được tạo ra một cách thủ công hoặc sử dụng Widget có sẵn là DefaultTabController, DefaultTabController hỗ trợ các tính năng cơ bản như khai bản như định nghĩa số lượng các Tab
DefaultTabController( // The number of tabs / content sections to display. length: 3, child: // Complete this code in the next step. );
TabBar
TabBar dùng để chứa các Tab, tạo ra các Tab, hãy xem hình dưới đây để có thể hình dung rõ hơn về mối quan hệ giữa TabBar và Tab
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)), ], ), ), ), );
Trong ví dụ trên chúng ta đã sử dụng DefaultTabController để chứa một TabBar, trong TabBar lại có chứa 3 Tab
Câu hỏi đặt ra là bạn có thể đặt nhiều TabBar trong một DefaultTabController không? Flutter sẽ hỗ trợ bạn việc này tuy nhiên DefaultTabController chỉ làm việc với một TabBar gần với nó nhất, để hoạt động được nhiều TabBar bạn hãy dùng đến TabController được điều khiển bởi chính bạn (điều khiển thủ công)
TabBarView
Sử dụng TabBarView để chứa các nội dung tương ứng với mỗi Tab trên TabBar.
TabBarView ( children: [ Icon(Icons.directions_car), Icon(Icons.directions_transit), Icon(Icons.directions_bike), ], );
Trong ví dụ này chúng ta sẽ tạo ra một TabBar chứa 3 Tab và sử dụng DefaultTabController
TabController( {int initialIndex: 0, @required int length, @required TickerProvider vsync} )
DefaultTabController
const DefaultTabController( {Key key, @required int length, int initialIndex: 0, @required Widget child} )
const TabBar( {Key key, @required List 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 onTap, ScrollPhysics physics} )
const TabBarView( {Key key, @required List children, TabController controller, ScrollPhysics physics, DragStartBehavior dragStartBehavior: DragStartBehavior.start} )
Thuộc tính isScrollable có hay không cho phép tạo thanh cuộn ngang khi tổng chiều dài của các tab lớn hơn độ rộng màn hình. khi isScrollable được gán là True thì độ rộng của mỗi tab chứa vừa đủ nội dung của tab (Hình ảnh và văn bản) và xuất hiện thanh trượt ngang
Bạn hãy xem ví dụ dưới đây
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 Electrical")) ], ), ) ); } 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 Electrical")]), ], isScrollable: true, ); } }
Thuộc tính indicatorColor dùng để định dạng đường kẻ nền Tab đang được chọn, thuộc tính này sẽ bị vô hiệu lực nếu thuộc tính indicator được sử dụng
indicatorColor: Color(0xffE74C3C),
Ví dụ dưới đây sẽ tạo ra một đường kẻ (Line) màu đỏ khi tab được chọn
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 Electrical")) ], ), ) ); } 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 Electrical")]), ], /*isScrollable: true,*/ indicatorColor: Color(0xffE74C3C), ); } }
Thuộc tính indicatorWeight dùng để định dạng độ dày (Thickness) của đường kẻ (Line) phía dưới của Tab đang được chon
indicatorWeight: 10
Ví dụ dưới đây sẽ định dạng độ dày của đường kẻ (Line) lên 10 đơn vị khi tab được chọn
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 Electrical")]), ], /*isScrollable: true,*/ indicatorColor: Color(0xffE74C3C), indicatorWeight: 10, ); } }
Thuộc tính indicatorPadding dùng để chỉ định khoảng cách đệm (padding) của thanh ngang tới mép bên phải của tab
indicatorPadding: EdgeInsets.only(right: 20),
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 Electrical")]), ], /*isScrollable: true,*/ indicatorColor: Color(0xffE74C3C), indicatorWeight: 10, indicatorPadding: EdgeInsets.only(right: 20), ); } }
Thuộc tính indicator dùng để tạo hiệu ức khung cho Tab đang được chọn, khi thuộc tính indicator được sử dụng thì các thuộc tính indicatorColor, indicatorWeight và indicatorPadding sẽ bị vô hiệu hóa.
Sau đây là ví dụ cách dùng indicator
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 Electrical")]), ], indicator: ShapeDecoration ( shape: UnderlineInputBorder ( borderSide: BorderSide( color: Colors.transparent, width: 0, style: BorderStyle.solid ) ), gradient: LinearGradient(colors: [Color(0xff0081ff), Color(0xff01ff80)]) ) ); } }
thuộc tính labelColor dùng để chỉ định màu văn bản cho tab đang được chọn, thuộc tính unselectedLabelColor dùng để chỉ định màu cho các tab không được chọn
Color labelColor; Color unselectedLabelColor;
Chúng ta cùng tìm hiểu và xem kết quả ở ví dụ sau đây
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 Electrical")]), ], labelColor: Colors.red, unselectedLabelColor: Colors.black, ); } }
Thuộc tính labelPadding dùng để thêm vùng đệm (padding) vào cho các lable của từng tab
labelPadding: EdgeInsets.all( 20),
Cùng xem ví dụ sau nhé
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 Electrical")]), ], labelPadding: EdgeInsets.all( 20), ); } }
Thuộc tính labelStyle, unselectedLabelStyle dùng để định dạng văn bản (lable) khi tab đang được chọn hoặc không chọn
Trong vì dụ này lable được chọn sẽ được bôi đậm và có kích thước font size là 20, những lable không được chọn sẽ có font size là 18 và chữ thường
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 Electrical")]), ], labelStyle: TextStyle(fontWeight: FontWeight.bold, fontSize: 22), unselectedLabelStyle: TextStyle(fontStyle: FontStyle.normal, fontSize: 18), ); } }
onTap là một sự kiện (hàm) callback sẽ được gọi khi người dùng lựa chọn Tab trên TabBar
Chúng ta sẽ làm một ví dụ khi Tab được chọn sẽ đếm số lần Tab được chọn và ghi lại trên lable của Tab
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 createState() { return MyHomePageState(); } } class MyHomePageState extends State { 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('VTS OnTap 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; } }); }
Trên đây là toàn bộ hướng dẫn chi tiết sử dụng Flutter TabBar, Các bạn có câu hỏi gì liên hệ với tác giả Mr Dũng 098 333 0380. Các bạn mong muốn trở thành lập trình viên trên Mobile liên hệ công ty VTS chúng tôi nhận thực tập sinh hướng dẫn chi tiết lập trình Flutter từ A-Z
Bài trước: Ứng dụng Flutter đầu tiên “Hello Word”
Bài tiếp theo: Hướng dẫn và các ví dụ sử dụng Flutter BottomNavigationBar
11/11/2022
27/10/2022
25/10/2022
24/10/2022
22/08/2021
30/08/2021
14/10/2022
19/08/2021
21/01/2025
24/12/2024
22/08/2024
15/08/2024
08/08/2024
Khám phá sự khác biệt với phần mềm quản trị doanh nghiệp hàng đầu! Đăng ký ngay để sử dụng phần mềm miễn phí.
Nhanh tay đăng ký để được tư vấn dịch vụ miễn phí và tìm ra giải pháp tốt nhất cho nhu cầu của bạn!