Playing With Tab Bar and Tab View in Flutter

Deepak Shah
5 min readFeb 5, 2021

--

Tab bar allows you to organize and navigate between group of content that are related to each other which can be placed in different Tab View.

TabBar and TabBarView

Lets create a flutter project. Clean all the initial main.dart code with code as given below.

import 'package:flutter/material.dart';

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Playing With Tab Bar',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Playing With Tab Bar'),
);
}
}

class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);

final String title;

@override
_MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("Hello World"),
],
),
),
);
}
}

Lets say we want to make a tab bar with for Home, Restaurant and Hotel. To create Tab Bar which will appear in AppBar of the Screen as follows:

appBar: AppBar(
title: Text(widget.title),
bottom: TabBar(
tabs: [
Tab(
icon: Icon(Icons.home_outlined),
child: Text("Home"),
),
Tab(
//text: "Cultural Service",
icon: Icon(Icons.restaurant_outlined),
child: Text("Restaurant"),
),
Tab(
//text: "Cultural Service",
icon: Icon(Icons.hotel_outlined),
child: Text("Hotels"),
)
],
),

)

Replace appBar with above code.

Then Place TabBarView in the body of the Scaffold which will contain the view for each tab as follows:

body: Container(
child: TabBarView(
children: [
Center(
child: Text("Home Tab View"),
),
Center(
child: Text("Map Tab View"),
),
Center(
child: Text("Hotel Tab View"),
)
],
),
),

Now you have to wrap the whole return statement of Widget build inside DefaultController which will look like as follows:

Widget build(BuildContext context) {
return DefaultTabController(
length: 3,
child: Scaffold(...)
);
}

As we have three Tab so the value of the parameter length will be also 3.

Tab Bar and Tab View

Now lets say if you want to disable the swipe of the Tab Bar View to move next tab view. To do this put physics: NeverScrollableScrollPhysics() inside TabBarView as follows:

child: TabBarView(
physics: NeverScrollableScrollPhysics(),
children: [
Center(
child: Text("Home Tab View"),
),
Center(
child: Text("Map Tab View"),
),
Center(
child: Text("Hotel Tab View"),
)
],
)

Now you can use Tap on Tab Bar to go to next tab bar view.

Lets create forward and backward button at the bottom of the screen to navigate between Tab Bar View.

To do this at first we have to create a footer at the bottom. Use persistentFooterButtons inside Scaffold widget as follows:

child: Scaffold(
.....
persistentFooterButtons: [
Container(
width: MediaQuery.of(context).size.width,
height: 40,
padding: EdgeInsets.only(bottom: 0.0),
margin: EdgeInsets.only(bottom: 10.0, top: 0.0),
child: Center(
child: Text("Footer goes here"),
),
)
]
)
Footer

Now create a ListTile and Place forward and backward button inside footer. Use leading and trailing to place the icon at start and end of ListTile.

persistentFooterButtons: [
Container(
width: MediaQuery.of(context).size.width,
height: 40,
padding: EdgeInsets.only(bottom: 0.0),
margin: EdgeInsets.only(bottom: 10.0, top: 0.0),
child: Center(
child: ListTile(
leading: FloatingActionButton(
elevation: 4.0,
child: new Icon(Icons.arrow_back_outlined),
//backgroundColor: themeColor,
onPressed: () {

}),
trailing: FloatingActionButton(
elevation: 4.0,
child: new Icon(
Icons.arrow_forward_outlined,
),
//backgroundColor: themeColor,
onPressed: () {

}),
),
),
)
],
Footer with Button

After creating button lets create action on forward and backward action on Tap to move to next and previous view.

At first you have to use a mixin to your class called SingleTickerProviderStateMixin as follows:

class _MyHomePageState extends State<MyHomePage> with  SingleTickerProviderStateMixin {
}

Intialize pageNo and _tabController variable and create method for forward and backward action.

int pageNo = 0;
TabController _tabController;

void initState() {
_tabController = new TabController(
vsync: this,
length: 3,
);
}

void forwardTabPage() {
if (pageNo >= 0 && pageNo < 3) {
setState(() {
pageNo = pageNo + 1;
});
_tabController.animateTo(pageNo);
}
}

void backwardTabPage() {
if (pageNo >= 1 && pageNo < 3) {
setState(() {
pageNo = pageNo - 1;
});
_tabController.animateTo(pageNo);
}
}

Also call the forwardTabPage() and backwardTabPage() on forward and backward button tap.

Put the _tabController inside TabBar and TabBarView.

bottom: TabBar(
controller: _tabController,
......
)
child: TabBarView(
controller: _tabController,
physics: NeverScrollableScrollPhysics(),
children: [
......
]
)

You can also put onTap action in TabBar and set the state of pageNo variable.

bottom: TabBar(
controller: _tabController,
onTap: (val){
setState(() {
pageNo=val;
});
},
tabs: [...]
)

Full code of main.dart is given below:

import 'package:flutter/material.dart';

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Playing With Tab Bar',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Playing With Tab Bar'),
);
}
}

class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);

final String title;


@override
_MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
int pageNo = 0;
TabController _tabController;

void initState() {
_tabController = new TabController(
vsync: this,
length: 3,
);
}

void forwardTabPage() {
if (pageNo >= 0 && pageNo < 3) {
setState(() {
pageNo = pageNo + 1;
});
_tabController.animateTo(pageNo);
}
}

void backwardTabPage() {
if (pageNo >= 1 && pageNo < 3) {
setState(() {
pageNo = pageNo - 1;
});
_tabController.animateTo(pageNo);
}
}

@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
title: Text(widget.title),
bottom: TabBar(
controller: _tabController,
onTap: (val){
setState(() {
pageNo=val;
});
},
tabs: [
Tab(
icon: Icon(Icons.home_outlined),
child: Text("Home"),
),
Tab(
//text: "Cultural Service",
icon: Icon(Icons.restaurant_outlined),
child: Text("Restaurant"),
),
Tab(
//text: "Cultural Service",
icon: Icon(Icons.hotel_outlined),
child: Text("Hotels"),
)
],
),

),
body: Container(

child: TabBarView(
controller: _tabController,
physics: NeverScrollableScrollPhysics(),
children: [
Center(
child: Text("Home Tab View"),
),
Center(
child: Text("Map Tab View"),
),
Center(
child: Text("Hotel Tab View"),
)
],
),
),
persistentFooterButtons: [
Container(
width: MediaQuery.of(context).size.width,
height: 40,
padding: EdgeInsets.only(bottom: 0.0),
margin: EdgeInsets.only(bottom: 10.0, top: 0.0),
child: Center(
child: ListTile(
title: Center(
child: Text("Page No: ${(pageNo+1).toString()}"),
),
leading: (pageNo!=0)?FloatingActionButton(
elevation: 4.0,
child: new Icon(Icons.arrow_back_outlined),
onPressed: () {
backwardTabPage();

}):SizedBox(),
trailing: (pageNo!=2)?FloatingActionButton(
elevation: 4.0,
child: new Icon(
Icons.arrow_forward_outlined,
),
onPressed: () {
forwardTabPage();
}):SizedBox(),
),
),
)
],
),
);
}
}

Happy Fluttering!

--

--

Deepak Shah
Deepak Shah

Written by Deepak Shah

Software Engineer | Geospatial Application Developer | Machine Learning Developer |Love Trekking.Open For Collaboration. Write me :shahkrdeepak at gmail dot com

No responses yet