TabBarView with dynamic container height and futurebuilder Flutter - flutter

I'm using a SizedBox and passing the screen height to it, but I have a RenderFlex overflowed error.
This is the structure of my code:
return DefaultTabController(
length: 2,
initialIndex: 0,
child: Scaffold(
drawer: const NavigationDrawerWidget(),
appBar: CustomAppBar(),
body: SingleChildScrollView(
child: Column(
children: [
TabBar(
isScrollable: true,
tabs: myTabs,
),
SizedBox(
height: (MediaQuery.of(context).size.height),
child: TabBarView(
children: [
futureBuilder,
const Icon(Icons.directions_bike),
],
),
)
],
),
)),
);
FutureBuilder returns a container where the height is varied and has other expansive children. How can I get rid of using SizedBox and pass a height to it? I tried using Expanded in place of SizedBox but got errors.

Try using NestedScrollView
return Scaffold(
body: DefaultTabController(
length: 2,
initialIndex: 0,
child: NestedScrollView(
headerSliverBuilder: (context, innerBoxIsScrolled) {
return [
SliverAppBar(
bottom: TabBar(isScrollable: true, tabs: [
Tab(
icon: Icon(Icons.ac_unit),
),
Tab(
icon: Icon(Icons.ac_unit),
),
]))
];
},
body: TabBarView(
children: [
SingleChildScrollView(
child: Container(
color: Colors.red,
child: Column(
children: [
for (int i = 0; i < 34; i++)
Container(
height: kToolbarHeight,
color: i.isEven ? Colors.amber : Colors.pink,
)
],
),
),
),
const Icon(Icons.directions_bike),
],
),
),
),
);

Related

Back Button displaced title of AppBar

Like the title, i have created a button with Navigator.push() into a new page, the page auto generates a back button on the appBar, i appreciated that autogenerated back button but i want the back button to not displace my title's positioning, is that possible?
Below is my code for the button to enter this page:
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) {
return FeedTest();
},
),
);
This is my full code for the new page:
Widget build(BuildContext context) {
return ScrollConfiguration(
behavior: MyBehavior(),
child: SafeArea(
child: DefaultTabController(
length: 2,
child: Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.grey[850],
title: Flex(
direction: Axis.horizontal,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'images/logo2.png',
isAntiAlias: true,
scale: 1.8,
fit: BoxFit.fitHeight,
alignment: Alignment.center,
)
]),
bottom: TabBar(
indicatorColor: Colors.white,
tabs: [
Tab(
text: 'Submit Feedback',
),
Tab(
text: 'Submit Testimony',
)
],
),
),
body: TabBarView(
children: [SubmitFeedback(), SubmitTestimony()],
),
),
),
),
);
}
P.S. Title image has been blurred for privacy purposes
centerTitle: true is used to make the title center in AppBar
AppBar(
centerTitle: true,
...
)
Output:
Use centerTitle: true like below.
AppBar(
centerTitle: true, // this is all you need
//Rest Code here
)
I upload the full code like below.
Widget build(BuildContext context) {
return ScrollConfiguration(
behavior: MyBehavior(),
child: SafeArea(
child: DefaultTabController(
length: 2,
child: Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
centerTitle: true,
elevation: 0,
backgroundColor: Colors.grey[850],
title: Flex(
direction: Axis.horizontal,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'images/logo2.png',
isAntiAlias: true,
scale: 1.8,
fit: BoxFit.fitHeight,
alignment: Alignment.center,
)
]),
bottom: TabBar(
indicatorColor: Colors.white,
tabs: [
Tab(
text: 'Submit Feedback',
),
Tab(
text: 'Submit Testimony',
)
],
),
),
body: TabBarView(
children: [SubmitFeedback(), SubmitTestimony()],
),
),
),
),
);
}

Flutter - How to add custom tabbar inside sliverappbar?

I'm trying to implement a custom tab bar widget inside a SliverAppBar. So far I've tried wrapping my CustomTabBar within a PreferredSize widget.
Here's my code:
Widget _buildBody(){
return NestedScrollView(
headerSliverBuilder: (BuildContext context, bool boxIsScrolled) {
return <Widget>[
SliverAppBar(
leading: Container(),
backgroundColor: Colors.transparent,
expandedHeight: 200.0,
flexibleSpace: FlexibleSpaceBar(
collapseMode: CollapseMode.pin,
background: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(
"Item 1"
),
Text(
"Item 2"
),
Text(
"Item 3"
)
],
)
]),
),
bottom: PreferredSize(
preferredSize: Size.fromHeight(kToolbarHeight),
child: CustomTabWidget(
items: ['Challenge', 'My friends'],
activeColor: secondaryColor,
currentIndex: currentIndex,
backgroundColor: tabColor,
activeTextColor: Colors.white,
backgroundTextColor: Colors.white,
onTabSelect: (int index) {
onLeaderboardTabSelect(index);
},
),
),];
},
body: ListView.separated(
itemCount: 50,
itemBuilder: (context, index) {
return ListTile(
title: Text('row $index'),
);
},
separatorBuilder: (context, index) {
return Divider();
},
) // should return listview depending on the tab
);
}
CustomTabWidget
Widget build(BuildContext context) {
return Container(
height: height,
decoration: BoxDecoration(
color: backgroundColor,
borderRadius: BorderRadius.circular(
30.0,
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: _buildItems(context),
),
);
}
The code successfully shows the my custom tab bar widget but whenever I scroll down or tap another tab, it disappears.
I might have overlooked something within the code.
Can anyone help me?
this work on my project
class TabBarInSliverAppbar extends StatelessWidget {
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
body: CustomScrollView(
slivers: [
SliverAppBar(
title: Text("Tabbar in SliverAppbar Example"),
pinned: true,
floating: true,
bottom: TabBar(
tabs: <Widget>[
Tab(
text: "First Tab",
),
Tab(
text: "Second Tab",
),
],
),
),
SliverToBoxAdapter(
child: TabBarView(
children: <Widget>[
Center(
child: Text("First Tab"),
),
Center(
child: Text("Second Tab"),
),
],
),
),
],
),
),
);
}
}
you can also checki this link :Flutter TabBar and SliverAppBar that hides when you scroll down

Display TabBar in body of scaffold

I'm want to display a tabbar as it is used with the appbar, but in the middle of the scaffold body. Is it possible?
I have this code, but the TabBarView breaks the ui. If I comment the TabBarView, the TabBars are displayed correctly. What is wrong with the code? In case it's possible to use it this way..
#override
void initState() {
super.initState();
_tabController = TabController(length: 2, vsync: this);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: <Widget>[
Text('Some other random content'),
TabBar(
controller: _tabController,
isScrollable: true,
tabs: <Widget>[
Tab(
child: Text(
'Posts',
style: TextStyle(
fontSize: 18.0,
color: Colors.black87,
),
),
),
Tab(
child: Text(
'Fotos',
style: TextStyle(
fontSize: 18.0,
color: Colors.black87,
),
),
),
],
),
TabBarView(
controller: _tabController,
children: <Widget>[
Center(
child: Text("User"),
),
Center(
child: Text("Email"),
),
],
),
],
),
);
}
Just Change ListView to Column and add SingleChildScrollView
SingleChildScrollView(
child: Column(
children: <Widget>[]
),
)
Hey i guess it's already too late but maybe it helps others.
If you just want to have your tabbar e.g. in the middle of the screen to divide your screen in 2 sections (top: content, bottom: tabbar) you can place your scaffold inside a column, e.g. following:
#override
Widget build(BuildContext context) {
return Column(
children: [
Expanded(
flex: 1,
child: Center(
child: Text("Header"),
),
),
Expanded(
flex: 1,
child: DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
flexibleSpace: TabBar(
tabs: [
Tab(text: "First"),
Tab(text: "Second"),
Tab(text: "Third"),
],
),
),
body: TabBarView(
children: [
Center(child: Text("First screen")),
Center(child: Text("Second screen")),
Center(child: Text("Third screen")),
],
),
),
),
),
],
);
}
Let me know if this fits your needs / if you need further help :-)

How to vertically center text/title in Flutter using SliverAppBar?

I am trying to set up a SliverAppBar in a CustomScrollView using Flutter, and can't get to vertically center the title.
I already tried this solution (and this SO question is exactly what I want to do) but fortunately, it didn't work for me.
Here is my build method:
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
pinned: true,
expandedHeight: 200,
//backgroundColor: Colors.transparent,
flexibleSpace: FlexibleSpaceBar(
titlePadding: EdgeInsets.zero,
centerTitle: true,
title: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text("Should be centered", textAlign: TextAlign.center),
],
),
background: Image.asset("assets/earth.jpg", fit: BoxFit.cover),
),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.menu),
tooltip: "Menu",
onPressed: () {
// onPressed handler
},
),
],
),
SliverFixedExtentList(
itemExtent: 50,
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
alignment: Alignment.center,
color: Colors.green,
child: Text("Index n°$index"),
);
},
),
)
],
),
);
}
I really don't understand what is wrong and why it isn't centered. I observed that the column is way too big when setting mainAxisSize to mainAxisSize.max.
Any idea?
Thanks in advance!
I tinkered around a bit in your code and was able to center it. So the main problem here was the expandedHeight. This height expands the SliverAppBar both upwards and downwards meaning that half of that 200 was always above the screen. Taking that into consideration, you would be trying to center the text in only the bottom half of the app bar. The simplest way was to just use Flexible to size the items relative to their container. Here's the working code:
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
pinned: true,
expandedHeight: 200,
//backgroundColor: Colors.transparent,
flexibleSpace: FlexibleSpaceBar(
titlePadding: EdgeInsets.zero,
centerTitle: true,
title: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Flexible(
flex: 3,
child: Container(),
),
Flexible(
flex: 1,
child:
Text("Should be centered", textAlign: TextAlign.center),
),
Flexible(
flex: 1,
child: Container(),
),
],
),
background: Image.asset("assets/earth.png", fit: BoxFit.cover),
),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.menu),
tooltip: "Menu",
onPressed: () {
// onPressed handler
},
),
],
),
SliverFixedExtentList(
itemExtent: 50,
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
alignment: Alignment.center,
color: Colors.green,
child: Text("Index n°$index"),
);
},
),
)
],
),
);
}
A way without empty containers
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
pinned: true,
expandedHeight: 200,
flexibleSpace: FlexibleSpaceBar(
titlePadding: EdgeInsets.zero,
centerTitle: true,
title: SizedBox(
height: 130,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("Should be centered", textAlign: TextAlign.center),
],
),
),
background: Image.asset("assets/earth.png", fit: BoxFit.cover),
),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.menu),
tooltip: "Menu",
onPressed: () {
// onPressed handler
},
),
],
),
SliverFixedExtentList(
itemExtent: 50,
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
alignment: Alignment.center,
color: Colors.green,
child: Text("Index n°$index"),
);
},
),
)
],
),
);
}
Instead of using a FlexibleSpaceBar use a different Widget.
flexibleSpace: Padding(
padding: EdgeInsets.all(4),
child: Container(),
}),
),
Kinda like what Pedro said earlier, you can instead use the flexibleSpace parameter in SliverAppBar, and then center things from there. This is what I did.
SliverAppBar(
flexibleSpace: Center(
child: Text("27 is my favorite number")
)
)

TabView inside CustomScrollView

Wrapping TabBarView with SliverFillRemaining (fill remaining empty space like Expanded) gives the following error output.
flutter: A RenderPositionedBox expected a child of type RenderBox but received a child of type
flutter: RenderSliverList.
TabController tabContoller;
#override
void initState() {
tabContoller = new TabController(
vsync: this,
length: 3,
);
#override
Widget build(BuildContext context) {
return new Scaffold(
floatingActionButton:floatActionBtn(...),
bottomNavigationBar: bottomNavigationBar(...),
appBar: apBar(),
body: Stack(
children: <Widget>[
CustomScrollView(
slivers: <Widget>[
SliverAppBar(
backgroundColor: Colors.transparent,
automaticallyImplyLeading: false,
expandedHeight: 195.0,
flexibleSpace: FlexibleSpaceBar(
background: new Stack(
children: <Widget>[
...
]),
),
),
new SliverFillRemaining(
child: TabBarView(
controller: tabContoller,
children: <Widget>[
Tab(...),
Tab(...),
Tab(...)
],
),
),
],
),
],
)
Don't forget the DefaultTabController, this code is working fine:
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 3,
child: Container(
child: CustomScrollView(slivers: <Widget>[
SliverAppBar(),
new SliverFillRemaining(
child: TabBarView(
children: <Widget>[
Text("Tab 1"),
Text("Tab 2"),
Text("Tab 3"),
],
),
),
])),
);
}
You can use NestedScrollView like this
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 3,
child: Scaffold(
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
forceElevated: innerBoxIsScrolled,
automaticallyImplyLeading: false,
expandedHeight: 195.0,
flexibleSpace: FlexibleSpaceBar(
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(_, int index) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TabBar(
labelColor: AppColors.black,
unselectedLabelColor: AppColors.gray,
indicatorColor: AppColors.primaryColor,
indicatorWeight: 4,
indicatorPadding: EdgeInsets.symmetric(horizontal: 16),
labelPadding: EdgeInsets.zero,
tabs: [
Text("FIRST"),
Text("SECOND"),
Text("THIRD"),
],
)
],
);
},
childCount: 1,
),
),
];
},
body: TabBarView(
children: <Widget>[
Text("FIRST TAB"),
Text("SECOND TAB"),
Text("THIRD TAB"),
],
),
),
),
);
}