Reputation: 8666
I am trying to create a tabbed bar layout screen without the AppBar though. I have already referred to the solution on this link: how to create the tab bar without app bar in flutter? but it is not working for me. Here is what my screen looks like when I place TabBar in the appbar:
parameter:
My TabBar has moved to the top left corner under the status bar and its all squeezed in one corner. It's almost as if it's not there at all.
When I use the AppBar class but only pass the bottom:
parameter here is what happens:
There is an ugly space on top of the TabBar which is obviously meant for the AppBar title. Here is my code:
return new Scaffold(
appBar: new TabBar(
tabs: widget._tabs.map((_Page page){
return Text(page.tabTitle);
}).toList(),
controller: _tabController,
isScrollable: true,
),
backgroundColor: Colors.white,
body: new TabBarView(
controller: _tabController,
children: widget._tabs.map((_Page page){
return new SafeArea(
top:false,
bottom: false,
child: (page.page == Pages.cart?new CartHomeScreen():_lunchesLayout())
);
}).toList()
),
);
How can I just have TabBar without that space on top and is it possible to make the two tab items and their indicators to stretch and fill the side spaces?
Upvotes: 58
Views: 98577
Reputation: 267434
You won't need to use appBar
property:
DefaultTabController(
length: 2,
child: Scaffold(
body: Column(
children: [
TabBar( // <-- Your TabBar
tabs: [
Tab(icon: Icon(Icons.call)),
Tab(icon: Icon(Icons.settings)),
],
),
Expanded(
child: TabBarView( // <-- Your TabBarView
children: [
Container(color: Colors.blue),
Container(color: Colors.red),
],
),
),
],
),
),
)
Upvotes: 17
Reputation: 2786
Follow below code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
TabController _tabController;
@override
void initState() {
_tabController = new TabController(length: 2, vsync: this);
super.initState();
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
height: MediaQuery.of(context).size.height / 2,
child: Center(
child: Text(
"Tabbar with out Appbar",
style: TextStyle(
color: Colors.white, fontWeight: FontWeight.bold),
),
),
color: Colors.blue,
),
TabBar(
unselectedLabelColor: Colors.black,
labelColor: Colors.red,
tabs: [
Tab(
text: '1st tab',
),
Tab(
text: '2 nd tab',
)
],
controller: _tabController,
indicatorSize: TabBarIndicatorSize.tab,
),
Expanded(
child: TabBarView(
children: [
Container(child: Center(child: Text('people'))),
Text('Person')
],
controller: _tabController,
),
),
],
),
),
);
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
}
view the result
Upvotes: 51
Reputation: 41
Give toolbarHeight : 0 for Appbar
appBar: AppBar(
toolbarHeight: 0, // <--- Add this line to app bar
bottom: TabBar(tabs: [
Tab(
text: "Transactions",
),
Tab(
text: "Transfer",
)
]),
),
Upvotes: 1
Reputation: 629
By setting the toolbarHeight property of a AppBar to zero will remove them toolbar and leaving the tabbar at the bottom as set by theme.
Scafford(
appBar: AppBar(
toolbarHeight: 0,
bottom: TabBar(...)
)
)
Upvotes: 1
Reputation: 302
Here you go. This is a widget, without any scafold or material app around it, so make sure you provide that tree yourself. Otherwise it's ready for copy-paste
import 'package:flutter/material.dart';
class MyWidget extends StatefulWidget {
const MyWidget({super.key});
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget>
with SingleTickerProviderStateMixin {
late final TabController _tabController;
@override
void initState() {
_tabController = TabController(length: 2, vsync: this);
super.initState();
}
@override
Widget build(BuildContext context) {
return Column(children: [
TabBar(controller: _tabController, tabs: const [
Tab(icon: Icon(Icons.cookie_outlined)),
Tab(icon: Icon(Icons.no_food))
]),
Expanded(
child: TabBarView(controller: _tabController, children: [
Container(color: Colors.greenAccent),
Container(color: Colors.yellowAccent)
]))
]);
}
}
Upvotes: 4
Reputation: 181
From CopsOnRoad's answer, I've created a hidden TabBar like this:
Scaffold(
body: Column(
children: [
TabBar( // <-- Hidden TabBar
indicator: BoxDecoration(),
tabs: [
SizedBox.shrink(),
SizedBox.shrink(),
],
),
Expanded(
child: TabBarView( // <-- Your TabBarView
children: [
Container(color: Colors.blue),
Container(color: Colors.red),
],
),
),
],
),
)
Upvotes: 5
Reputation: 28886
Directly use TabBar
in appBar
property:
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: TabBar(
tabs: [
Tab(icon: Icon(Icons.call)),
Tab(icon: Icon(Icons.message)),
],
),
body: TabBarView(
children: [
Center(child: Text('Call')),
Center(child: Text('Message')),
],
),
),
);
}
Upvotes: 6
Reputation: 519
Just use toolbarHeight
property in AppBar
widget with kMinInteractiveDimension
value as shown below:
Scaffold(
appBar: AppBar(
toolbarHeight: kMinInteractiveDimension,
bottom: TabBar(
controller: _tabController,
tabs: [], // your tab bars
),
),
body: TabBarView(
controller: _tabController,
children: [], // your tab views
),
);
Upvotes: 7
Reputation: 7143
It's very simple, all what you have to provide is height
to your TabView
.
Here is a simple example. You can either use DefaultTabController
or TabController
. In order to fully customizable, I'll use TabController
.
_getTabBar
function return list of tabs.
TabBar _getTabBar() {
return TabBar(
tabs: <Widget>[
Tab(icon: Icon(Icons.home, color: Colors.redAccent)),
Tab(icon: Icon(Icons.settings, color: Colors.redAccent)),
],
controller: tabController,
);
}
_getTabBarView
take list of widgets as input argument and creates a tab view.
TabBarView _getTabBarView(tabs) {
return TabBarView(
children: tabs,
controller: tabController,
);
}
SafeArea
is used to move content below status bar. _getTabBarView
is wrapped with a Container
so that we can allocate a height. This is one way of allocating height, you can use some other way also.
So here is the full code, wrap within a MaterialApp
and you have got a fully customizable tab bar and view. life-cycle methods are used to create and dispose TabController
import 'package:flutter/material.dart';
class TabControllerScreen extends StatefulWidget {
@override
_TabControllerScreenState createState() => _TabControllerScreenState();
}
class _TabControllerScreenState extends State<TabControllerScreen> with SingleTickerProviderStateMixin {
TabController tabController;
@override
void initState() {
super.initState();
tabController = TabController(length: 2, vsync: this);
}
@override
void dispose() {
tabController.dispose();
super.dispose();
}
TabBar _getTabBar() {
return TabBar(
tabs: <Widget>[
Tab(icon: Icon(Icons.home, color: Colors.redAccent)),
Tab(icon: Icon(Icons.settings, color: Colors.redAccent)),
],
controller: tabController,
);
}
TabBarView _getTabBarView(tabs) {
return TabBarView(
children: tabs,
controller: tabController,
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: <Widget>[
_getTabBar(),
Container(
height: 100,
child: _getTabBarView(
<Widget>[
Icon(Icons.home),
Icon(Icons.settings),
],
),
)
],
),
),
);
}
}
Upvotes: 4
Reputation: 40433
Your first screenshot actually shows it working just fine - the issue is that 'fine' isn't quite what you expect. The default text color is white for tabbar, so your labels aren't showing and instead just the bottom line is, which is what you see at the top left. Also, TabBar is a preferred size widget already, but it doesn't have the same height as an AppBar so if that's what you're going for, it won't look like it.
Here's an example that makes it look like the app bar. kToolbarHeight
is the same constant that AppBar uses.
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget {
@override
State<StatefulWidget> createState() => new MyAppState();
}
class MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'msc',
home: new DefaultTabController(
length: 2,
child: new Scaffold(
appBar: new PreferredSize(
preferredSize: Size.fromHeight(kToolbarHeight),
child: new Container(
color: Colors.green,
child: new SafeArea(
child: Column(
children: <Widget>[
new Expanded(child: new Container()),
new TabBar(
tabs: [new Text("Lunches"), new Text("Cart")],
),
],
),
),
),
),
body: new TabBarView(
children: <Widget>[
new Column(
children: <Widget>[new Text("Lunches Page")],
),
new Column(
children: <Widget>[new Text("Cart Page")],
)
],
),
),
),
);
}
}
Which results in this:
Edit:
As noted in the comments and from this github issue, you could also use the flexibleSpace property of the AppBar to hold the tabbar to basically the same effect:
return new DefaultTabController(
length: 3,
child: new Scaffold(
appBar: new AppBar(
flexibleSpace: new Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
new TabBar(
tabs: [
new Tab(icon: new Icon(Icons.directions_car)),
new Tab(icon: new Icon(Icons.directions_transit)),
new Tab(icon: new Icon(Icons.directions_bike)),
],
),
],
),
),
),
);
Upvotes: 86
Reputation: 116
Just use the flexiblespace prop and not the bottom prop of the appBar. All in the safeArea widget and you can add some vertical padding.
home: SafeArea(
top: true,
child: Padding(
padding: const EdgeInsets.only(top: 10.0),
child: DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
flexibleSpace: TabBar(
tabs: [
Tab(icon: Icon(Icons.1)),
Tab(icon: Icon(Icons.2)),
Tab(icon: Icon(Icons.3)),
],
),
),
body: TabBarView(
children: [
Icon(Icons.1),
Icon(Icons.2),
Icon(Icons.3),
],
),
),
),
),
)
Upvotes: 4
Reputation: 505
I take the code from rmtmckenzie but only to create a widget without material app
return new DefaultTabController(
length: 3,
child: new Scaffold(
appBar: new PreferredSize(
preferredSize: Size.fromHeight(kToolbarHeight),
child: new Container(
height: 50.0,
child: new TabBar(
tabs: [
Tab(icon: Icon(Icons.directions_car,color: Colors.grey,)),
Tab(icon: Icon(Icons.directions_transit,color: Colors.grey)),
Tab(icon: Icon(Icons.directions_bike,color: Colors.grey)),
],
),
),
),
body: TabBarView(
children: [
Icon(Icons.directions_car),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
],
),
),
);
Upvotes: 15