Force flutter's TabBarView to fit to its content - flutter

How can I force TabBarView to take min height possible to fit its content?
import 'package:flutter/material.dart';
void main() {
runApp(TabBarDemo());
}
class TabBarDemo extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: 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('Tabs Demo'),
),
body: Column(children: [
Text('Header Widget'),
Expanded(
child: TabBarView(
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.directions_car),
Icon(Icons.directions_car),
],
),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
],
),
),
Text('Footer Widget')
]),
),
),
);
}
}

Use BoxConstraint to restrict the height of TabBarView
Column(children: [
Text('Header Widget'),
Container(
constraints: BoxConstraints(
maxHeight: 100.0,
),
child: TabBarView(
children: [
Container(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.directions_car),
Icon(Icons.directions_car),
],
),
),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
],
),
),
Text('Footer Widget')
]),
Output:
Refer Blog:
https://medium.com/flutterworld/flutter-how-to-set-the-minimum-height-to-widget-36967b310ffe

Related

TabBar height expaned to rest of the screen

On one page I have DropDownSearch, SizedBox, TextButton and Tabs. Everything works fine but I have problem to set TabBarView height to be flexible to the bottom of the screen. I tried Flexible, Expanded (error: RenderFlex children have non-zero flex but incoming height constraints are unbounded) and Container/SizedBox with height: MediaQuery.of(context).size.height (error: A RenderFlex overflowed by 225 pixels on the bottom).
Any idea how to set the height of Container to fill rest of the screen? Or use different widget?
Thanks!
body: Column(
children: [
DropdownSearch<String>( ... )
const SizedBox(
width: 10,
),
TextButton(
onPressed: () {
setState(() {
});
},
child: Text('Click me',),
),
DefaultTabController(
length: 3,
child: Column(
children: [
Container(
child: TabBar(
tabs: [
Tab(icon: Icon(Icons.directions_car)),
Tab(icon: Icon(Icons.directions_transit)),
Tab(icon: Icon(Icons.directions_bike)),
],
),
),
SizedBox(
height: MediaQuery.of(context).size.height,
child: TabBarView(
children: [
Icon(Icons.directions_car),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
],
),
),
],
),
),
Instead of giving TabBarView screen height, wrap it with Expanded to get height as much as possible. ,try this:
Column(
children: [
SizedBox(
width: 10,
),
TextButton(
onPressed: () {
setState(() {});
},
child: Text(
'Click me',
),
),
Expanded( // <--- add this
child: DefaultTabController(
length: 3,
child: Column(
children: [
Container(
child: TabBar(
tabs: [
Tab(icon: Icon(Icons.directions_car)),
Tab(icon: Icon(Icons.directions_transit)),
Tab(
icon: Icon(
Icons.directions_bike,
)),
],
),
),
Expanded(// <--- add this
child: TabBarView(
children: [
Icon(Icons.directions_car),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
],
),
),
],
),
),
)
],
)
Wrap with Expanded widget to get available space. If you set full height on TabBarView there will be no space left for parent widget.
body: Column(children: [
// DropdownSearch<String>( ... )
const SizedBox(
width: 10,
),
TextButton(
onPressed: () {
setState(() {});
},
child: Text(
'Click me',
),
),
Expanded( //this one
child: DefaultTabController(
length: 3,
child: Column(
children: [
Container(
child: TabBar(
tabs: [
Tab(icon: Icon(Icons.directions_car)),
Tab(icon: Icon(Icons.directions_transit)),
Tab(icon: Icon(Icons.directions_bike)),
],
),
),
Expanded( //this one
// height: MediaQuery.of(context).size.height,
child: TabBarView(
children: [
Icon(Icons.directions_car),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
],
),
),
],
),
),
),
]));

How to implement Column inside of TabBarView with SingleChildScrollView?

I have a tabBar and TabBarView in body of the Scaffold widget, which is wrapped with SingleChildScrollView.
I want to display Column widget in the TabBarView (in this case it is the fourth tab), but it returns the error with OverFlow since SingleChildScrollView only detects the first element of the Column.
Any way to display Column widget here?
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
automaticallyImplyLeading: false,
leadingWidth: 80,
actions: const [
SizedBox(
width: 117.0,
)
],
leading: CustomBackButton(
onTap: () => Navigator.of(context).pop(),
),
backgroundColor: Theme.of(context).colorScheme.monochrome[300],
brightness: Brightness.light,
centerTitle: true,
title: Text(
'hello',
style: Theme.of(context).textTheme.subtitle1,
),
elevation: 0,
bottom: PreferredSize(
child: Container(
color: Theme.of(context).colorScheme.monochrome[400],
height: 1.0,
),
preferredSize: const Size.fromHeight(1.0),
),
),
body: SingleChildScrollView(
padding: const EdgeInsets.only(bottom: 64),
physics: const AlwaysScrollableScrollPhysics(),
child: Column(
children: [
DefaultTabController(
length: 4,
initialIndex: 0,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TabBar(
indicatorWeight: 4.0,
indicatorColor:
viewState.player!.team!.primaryColor(context),
tabs: [
Tab(
child: Text(
'tab1',)
Tab(
child: Text(
'tab2',
Tab(
child: Text(
'tab3',)
Tab(
child: Text(
'tab4',)
],
),
SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: Container(
height: 472,
decoration: const BoxDecoration(
border: Border(
top: BorderSide(
color: Colors.grey,
width: 0.5,
),
),
),
child: TabBarView(
children: [
TabView1(),
TabView2()
TabView3()
Column(
children: [
_buildYearSelection()
ProfileTable(),]),
],
),
),
)
],
),
),
),
),
],
),
),
);
}
Just try with ListView instead of column
ListView(
shrinkWrap: true,
physics: ScrollPhysics(),
children: [
Text("data"),
SizedBox(height: 500,),
Text("data"),
SizedBox(height: 500,),
Text("data"),
SizedBox(height: 500,),
Text("data"),
SizedBox(height: 500,),
Text("data"),
],
),
Perhaps what you are trying to do is create a TabBar that hides itself when scrolled.
If that is the case then there is an easy way to achieve it using CustomScrollView.
Something like this:
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
elevation: 0.0,
title: Text("MY title"),
),
body: CustomScrollView(slivers: [
const SliverAppBar(
title: TabBar(
indicatorWeight: 4.0,
tabs: [
Tab(child: Text("Tab 1")),
Tab(child: Text("Tab 2")),
],
),
),
SliverFillRemaining(
child: TabBarView(children: [
Container(child: Text("Scr 1")),
Container(child: Text("Scr 2")),
]),
),
]),
),
);
Below is the complete code:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Home(),
);
}
}
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
elevation: 0.0,
title: Text("MY title"),
),
body: CustomScrollView(slivers: [
const SliverAppBar(
title: TabBar(
indicatorWeight: 4.0,
tabs: [
Tab(child: Text("Tab 1")),
Tab(child: Text("Tab 2")),
],
),
),
SliverFillRemaining(
child: TabBarView(children: [
Container(child: Text("Scr 1")),
Container(child: Text("Scr 2")),
]),
),
]),
),
);
}
}

How to nest tab in flutter?

How to nest tab view as a child of column in flutter?
I don't want to add tabs as a child of app bar bottom cause my tabs are not on top. It is somewhere in the body.
So I tried the above method & also I tried wrapping it inside a nested scaffold. Both of them seems not working.
Following is what I've tried.
body: SingleChildScrollView(
physics: BouncingScrollPhysics(),
child: Container(
child: Column(children: [
Container(
padding: EdgeInsets.all(10),
child: TextInput(
placeholder: 'Search',
leadingIcon: searchIcon,
),
),
DefaultTabController(
length: 3,
child: Column(
children: [
TabBar(
tabs: [
Tab(icon: Icon(Icons.directions_car)),
Tab(icon: Icon(Icons.directions_transit)),
Tab(icon: Icon(Icons.directions_bike)),
],
),
TabBarView(
children: [
Icon(Icons.directions_car),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
],
),
],
),
),
give a height to tabcontroller and then wrap tabbarview with expanded.
body: SingleChildScrollView(
physics: BouncingScrollPhysics(),
child: Container(
child: Column(children: [
Container(
height:10,
padding: EdgeInsets.all(10),
),
Container(
height:100,//add height as per your need
child:DefaultTabController(
length: 3,
child: Column(
children: [
TabBar(
tabs: [
Tab(icon: Icon(Icons.directions_car)),
Tab(icon: Icon(Icons.directions_transit)),
Tab(icon: Icon(Icons.directions_bike)),
],
),
Expanded(
child:TabBarView(
children: [
Icon(Icons.directions_car),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
],
),
),
],
),
),
),
])))

how to align left Tab on DefaulfTabController?

How to align left Tabs?
DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
title: Row(
children: <Widget>[
...
],
),
actions: <Widget>[
...
],
bottom: TabBar(
isScrollable: true,
tabs: [
Tab(text: 'Chat'),
Tab(child: Row(
children: <Widget>[
...
],
)),
]
),
),
),
);
I tried FlexibleSpace too. It's align left, but I need to add TabBar on bottom
You can copy paste run full code below
You can use PreferredSize and Align
code snippet
appBar: AppBar(
title: Text(widget.title),
bottom: PreferredSize(
preferredSize: const Size.fromHeight(20.0),
child: Align(
alignment: Alignment.centerLeft,
child: Container(
width: MediaQuery.of(context).size.width / 2,
child: TabBar(
isScrollable: true,
controller: _tabController,
tabs: [
Tab(text: 'Tab 1'),
Tab(text: 'Tab 2'),
Tab(text: 'Tab 3'),
Tab(text: 'Tab 4'),
Tab(text: 'Tab 5'),
],
),
),
),
),
)
working demo
full code
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
final appTitle = 'Tabs Demo';
return MaterialApp(
title: appTitle,
home: MyHomePage(title: appTitle),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
const MyHomePage({Key key, this.title}) : super(key: key);
#override
State<StatefulWidget> createState() {
return _MyHomePageState();
}
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
int _tabIndex = 0;
TabController _tabController;
#override
void initState() {
super.initState();
_tabController = TabController(vsync: this, length: 5);
}
void _toggleTab() {
_tabIndex = _tabController.index + 1;
_tabController.animateTo(_tabIndex);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
bottomNavigationBar: BottomAppBar(
notchMargin: 20,
child: new Row(
// mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
InkWell(
onTap: () {
_toggleTab();
},
child: Text(
'Next >',
style: TextStyle(fontSize: 20, color: Colors.red),
),
)
],
),
),
appBar: AppBar(
title: Text(widget.title),
bottom: PreferredSize(
preferredSize: const Size.fromHeight(20.0),
child: Align(
alignment: Alignment.centerLeft,
child: Container(
width: MediaQuery.of(context).size.width / 2,
child: TabBar(
isScrollable: true,
controller: _tabController,
tabs: [
Tab(text: 'Tab 1'),
Tab(text: 'Tab 2'),
Tab(text: 'Tab 3'),
Tab(text: 'Tab 4'),
Tab(text: 'Tab 5'),
],
),
),
),
),
),
body: TabBarView(
controller: _tabController,
children: [
Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: Icon(Icons.album),
title: Text('Hello 1'),
subtitle: Text('Click on Next Button to go to Tab 2.'),
),
],
),
),
Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: Icon(Icons.album),
title: Text('Hello 2'),
subtitle: Text('Click on Next Button to go to Tab 3'),
),
],
),
),
Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: Icon(Icons.album),
title: Text('Hello 3'),
subtitle: Text('The End'),
),
],
),
),
Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: Icon(Icons.album),
title: Text('Hello 4'),
subtitle: Text('The End'),
),
],
),
),
Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: Icon(Icons.album),
title: Text('Hello 5'),
subtitle: Text('The End'),
),
],
),
),
],
),
));
}
}

TabBar on bottom of app with Column

I am trying to put the TabBar on the bottom of the app.
It worked so far, yet I can't get the pages to work (TabBarView). It just looks black and unresponsive. The TabBar is unresponsive too. Have I taken the wrong approach?
Currently, it looks like that:
And the code looks like this:
import 'package:flutter/material.dart';
void main() => runApp(Bookkeeper());
class Bookkeeper extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: DefaultTabController(
length: 4,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
verticalDirection: VerticalDirection.up,
mainAxisSize: MainAxisSize.min,
children: [
AppBar(
backgroundColor: Color(0xFF3F5AA6),
title: Container(
padding: EdgeInsets.only(top: 8.0),
child: menu(),
),
),
TabBarView(
children: [
Icon(Icons.directions_car),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
Icon(Icons.directions_bike),
],
),
],
),
),
);
}
Widget menu() {
return TabBar(
tabs: [
Tab(
child: Container(
height: 45.0,
child: Column(
children:
[
Icon(Icons.euro_symbol),
Text(
"Transactions",
style: new TextStyle(
height: 1.5,
fontSize: 9.8,
color: Colors.white,
),
),
],
),
),
),
Tab(
child: Container(
height: 45.0,
child: Column(
children:
[
Icon(Icons.assignment),
Text(
"Bills",
style: new TextStyle(
height: 1.5,
fontSize: 9.5,
color: Colors.white,
),
),
],
),
),
),
Tab(
child: Container(
height: 45.0,
child: Column(
children:
[
Icon(Icons.account_balance_wallet),
Text(
"Balance",
style: new TextStyle(
height: 1.5,
fontSize: 9.5,
color: Colors.white,
),
),
],
),
),
),
Tab(
child: Container(
height: 45.0,
child: Column(
children:
[
Icon(Icons.settings),
Text(
"Options",
style: new TextStyle(
height: 1.5,
fontSize: 9.5,
color: Colors.white,
),
),
],
),
),
),
],
);
}
}
Use bottomNavigationBar to position the Tabs at the bottom of the screen
class Bookkeeper extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: DefaultTabController(
length: 4,
child: Scaffold(
appBar: AppBar(
backgroundColor: Color(0xFF3F5AA6),
title: Text("Title text"),
),
bottomNavigationBar: menu(),
body: TabBarView(
children: [
Container(child: Icon(Icons.directions_car)),
Container(child: Icon(Icons.directions_transit)),
Container(child: Icon(Icons.directions_bike)),
Container(child: Icon(Icons.directions_bike)),
],
),
),
),
);
}
Widget menu() {
return Container(
color: Color(0xFF3F5AA6),
child: TabBar(
labelColor: Colors.white,
unselectedLabelColor: Colors.white70,
indicatorSize: TabBarIndicatorSize.tab,
indicatorPadding: EdgeInsets.all(5.0),
indicatorColor: Colors.blue,
tabs: [
Tab(
text: "Transactions",
icon: Icon(Icons.euro_symbol),
),
Tab(
text: "Bills",
icon: Icon(Icons.assignment),
),
Tab(
text: "Balance",
icon: Icon(Icons.account_balance_wallet),
),
Tab(
text: "Options",
icon: Icon(Icons.settings),
),
],
),
);
}
}