flutter tab bar view inside scroll able column - flutter

I need to implement a tab bar in following formation:
AppBar
DropDown
TabBar
Slider
TabBarView
Problem is: I'm putting everything from dropdown to tab bar view inside a column which goes inside a SingleChildScrollView. Which does not work.
My code:
late TabController _tabController;
#override
void initState() {
super.initState();
_merchantProducts = _getMerchantData();
_tabController = TabController(length: 2, vsync: this);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
...app bar
),
body: SingleChildScrollView(
child: _buildItems(context),
),
);
}
Widget _buildItems(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 15),
Container(
padding: EdgeInsets.only(left: 10, right: 20),
child: AddressDropDown(),
),
SizedBox(
height: 20,
),
TabBar(
controller: _tabController,
indicatorColor: CustomColors.primary,
labelColor: CustomColors.primary,
unselectedLabelColor: CustomColors.grey,
isScrollable: true,
tabs: [
Tab(
text: 'All',
),
Tab(
text: 'Popular',
),
],
),
Center(
child: AdSliderCard(),
),
SizedBox(
height: 20,
),
TabBarView(
controller: _tabController,
children: [
_buildMerchantProductList(context),
_buildMerchantProductList(context),
],
),
],
);
}
Widget _buildMerchantProductList(BuildContext context) {
return ListContainer(
data: _merchantProducts,
isHorizontal: false,
isScrollable: true,
);
}
}
How to solve the issue?
UPDATE: I can make the TabBarView scrollable without an issue. I need to make the entire page scrollable.

In your builditems, better way to achieve what you need is to use CustomScrollView:
CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: SizedBox(height: 15),
),
SliverToBoxAdapter(
child: Container(
padding: EdgeInsets.only(left: 10, right: 20),
child: AddressDropDown(),
),
),
SliverToBoxAdapter(
child: SizedBox(height: 20),
),
SliverToBoxAdapter(
child: Container(
height: 50,
child: TabBar(
controller: _tabController,
indicatorColor: CustomColors.primary,
labelColor: CustomColors.primary,
unselectedLabelColor: CustomColors.grey,
isScrollable: true,
tabs: [
Tab(
text: 'All',
),
Tab(
text: 'Popular',
),
],
),
),
),
SliverToBoxAdapter(
child: Container(
height: 200,
child: Center(
child: AdSliderCard(),
),
),
),
SliverToBoxAdapter(
child: SizedBox(height: 20),
),
SliverFillRemaining(
child: TabBarView(
controller: _tabController,
children: [
_buildMerchantProductList(context),
_buildMerchantProductList(context),
],
),
),
],
)

Use CustomScrollView and SliverFillRemaining for TabBarView.
return Scaffold(
body: CustomScrollView(
slivers: [
const SliverAppBar(
title: Text("A"),
),
SliverList(
delegate: SliverChildListDelegate.fixed(
[
DropdownButton<String>(
value: dropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: (String? newValue) {
setState(() {
dropdownValue = newValue!;
});
},
items: <String>['One', 'Two', 'Free', 'Four']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
TabBar(
controller: _tabController,
isScrollable: true,
tabs: const [
Tab(
text: 'All',
),
Tab(
text: 'Popular',
),
],
),
Slider(value: .3, onChanged: (v) {}),
],
),
),
SliverFillViewport(
delegate: SliverChildListDelegate.fixed([
TabBarView(
physics: const NeverScrollableScrollPhysics(),
//*
controller: _tabController,
children: [
SingleChildScrollView(
physics: const NeverScrollableScrollPhysics(),
child: Column(
children: [
...List.generate(
33,
(index) => Text(
"tab A: $index",
),
)
],
),
),
SingleChildScrollView(
physics: const NeverScrollableScrollPhysics(),
child: Column(
children: [
...List.generate(
33,
(index) => Text(
"tab B: $index",
),
)
],
),
)
],
),
]),
)
],
),
);

Related

Sticky Custom TabBar Flutter

How to make sticky TabBar in this answer.
I Want category section to stick below app bar when I scroll down.
I followed this answer and want to make it sticky for better UX.
enter image description here
#override
Widget build(BuildContext context) {
return Container(
color: mainBackgroundColor,
child: SafeArea(
child: GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Scaffold(
backgroundColor: mainBackgroundColor,
appBar: PreferredSize(
preferredSize: Size(double.infinity, 65),
child: AppBarr(isAppBar: isAppBar, label: 'Current Affairs')),
body: NestedScrollView(
controller: _scrollController,
headerSliverBuilder: (context, value) {
return [
SliverToBoxAdapter(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
searchBar(),
SizedBox(height: mainpadding),
topStoriesText(),
SizedBox(height: mainpadding/2),
topStoriesCard(),
SizedBox(height: mainpadding/2),
],
)),
SliverToBoxAdapter(
child: categoryTab(),
),
];
},
body: Container(
padding: EdgeInsets.only(top: mainpadding/2),
child: TabBarView(
controller: _tabController,
children: [
Stack(
alignment: Alignment.center,
children: [
ListView.builder(
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
physics: const BouncingScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsets.only(bottom: mainpadding),
itemCount: isLoadingData?lists.length:lists.length+1,
itemBuilder: (context, index) {
if(isLoadingData==false){
if(index==lists.length){
return Padding(
padding: EdgeInsets.only(
top: mainpadding,
left: mainpadding/2,
right: mainpadding/2,
bottom: mainpadding/2
),
child: AppButton(
text: 'Load More...',
textcolor: whiteColor,
primarycolor: blackColor,
onPressed: (() {
paginatedData();
})),
);
}
}
final users = lists[index];
return all(users);
}
),
isLoadingData?
Container(
color: Color.fromARGB(45, 0, 0, 0),
)
:SizedBox(),
isLoadingData?
Container(
height: 100,
width: 100,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
shape: BoxShape.rectangle,
color: whiteColor,
boxShadow: [
BoxShadow(
offset: Offset(1, 3),
blurRadius: 5,
color: Colors.black.withOpacity(0.14))
],
),
child: Center(child: CircularProgressIndicator(color: blackColor,)),
)
:SizedBox(),
],
),
_buildTabContext(2),
_buildTabContext(200),
_buildTabContext(2),
_buildTabContext(50),
_buildTabContext(50),
_buildTabContext(50),
_buildTabContext(50),
],
),
),
),
),
),
),
);
}
categoryTab(){
return TabBar(
controller: _tabController,
labelColor: blackColor,
splashBorderRadius: BorderRadius.circular(10),
physics: BouncingScrollPhysics(),
padding: EdgeInsets.symmetric(horizontal: mainpadding/2),
indicatorColor: blackColor,
labelStyle: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600),
labelPadding: EdgeInsets.symmetric(vertical: 0,horizontal: mainpadding/1.5),
isScrollable: true,
tabs: [
Tab(text: 'All'),
Tab(text: 'General'),
Tab(text: 'International'),
Tab(text: 'Nation'),
Tab(text: 'Education'),
Tab(text: 'Economy'),
Tab(text: 'Sports'),
Tab(text: 'Tech')
]
);
}

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")),
]),
),
]),
),
);
}
}

ListView cannot scroll to max item inside listview builder

I'm trying to put a Listview inside Tab, here is my script
SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
margin: EdgeInsets.only(left: 10, right: 10),
child: TabBar(
controller: _controller,
onTap: (index) {
setState(() {
_selectedIndex = _controller.index;
});
},
indicatorColor: AppColors.primary,
tabs: [
Tab(
child: Text(
"Menu 1",
style: TextStyle(color: Colors.black),
textAlign: TextAlign.center,
),
),
Tab(
child: Text(
"Menu 2",
style: TextStyle(color: Colors.black),
textAlign: TextAlign.center,
),
),
Tab(
child: Text(
"Menu 3",
style: TextStyle(color: Colors.black),
textAlign: TextAlign.center,
),
),
],
),
),
Container(
height: MediaQuery.of(context).size.height,
margin: EdgeInsets.all(10),
child: TabBarView(
controller: _controller,
children: [
Column(
children: [
Expanded(
child: ListView.builder(
physics: NeverScrollableScrollPhysics(),
itemCount: 1000,
itemBuilder: (context, index) {
return ListTile(
title: Text(index.toString()),
);
},
),
),
],
),
Container(
child: Text("Articles Body"),
),
Container(
child: Text("User Body"),
),
],
),
),
],
),);
As you can i see in tab 1 , i'm trying to create list with 1000 item counts. But the result it is stuck to list number 14.
How can i fix it ? thanks in advance and sorry for my english
You have used "NeverScrollableScrollPhysics". This disables the scroll property.
Use "AlwaysScrollableScrollPhysics" instead, then you will be able to scroll.
You need remove this line from the ListView.builder():
physics: NeverScrollableScrollPhysics(),
to allow scrolling

How to make a container with tabview & listview occupy space upto bottom

I have implemented tab layout which consists of two tabs, each tab view has a listview, container with tabview & listview should occupy space upto bottom as of now i place static value of 400, so only up to 400 the listview appears, i need the list view to be appeared up to bottom. can you please me to fix this
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left:20.0,right:20.0),
child: Container(
color: Colors.white,
child: new TabBar(
controller: _controller,
labelColor: Colors.deepOrange,
tabs: [
new Tab(
icon: const Icon(Icons.description),
text: 'ABC',
),
new Tab(
icon: const Icon(Icons.assignment),
text: 'XYZ',
),
],
),
),
),
Padding(
padding: const EdgeInsets.only(left:20.0,right:20.0),
child: Container(
color: Colors.white,
height: 400.0,
child: new TabBarView(
controller: _controller,
children: <Widget>[
ListView(
children: <Widget>[
ListTile(
title: Text('Sun'),
),
ListTile(
title: Text('Moon'),
),
ListTile(
title: Text('Star'),
),
],
),
ListView(
children: <Widget>[
ListTile(
title: Text('Sun'),
),
ListTile(
title: Text('Moon'),
),
ListTile(
title: Text('Star'),
),
],
),
],
),
),
),
],
),
);
}
I have Used Expanded & Flex Widgets which solved the problem
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.only(left:20.0,right:20.0),
child: Container(
color: Colors.white,
child: new TabBar(
controller: _controller,
labelColor: Colors.deepOrange,
tabs: [
new Tab(
icon: const Icon(Icons.description),
text: 'Current Openings',
),
new Tab(
icon: const Icon(Icons.assignment),
text: 'Applied Jobs',
),
],
),
),
),
flex: 1,
),
Expanded(
child: Padding(
padding: const EdgeInsets.only(left:20.0,right:20.0,bottom: 10.0),
child: Container(
color: Colors.white,
child: new TabBarView(
controller: _controller,
children: <Widget>[
ListView(
children: <Widget>[
ListTile(
title: Text('Sun'),
),
],
),
ListView(
children: <Widget>[
ListTile(
title: Text('Sun'),
),
],
),
],
),
),
),
flex: 9,
),
],
),
);
}

Is it possible to have Tab Bar with content before in Flutter?

I just wanted to ask, if it is possible to have Tab Bar View in Flutter with content before tabs (I mean that the Tabs are for example in the middle of the screen and they have content before - e.g. profile information - like Instagram and its profile section).
Example of what I mean here
I have already tried the default Tab View, but it is not what I want.
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
flexibleSpace: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TabBar(
labelColor: Colors.teal,
labelStyle: TextStyle(
fontWeight: FontWeight.bold,
),
unselectedLabelColor: Colors.black45,
unselectedLabelStyle: TextStyle(
fontWeight: FontWeight.normal
),
tabs: [
Tab(
icon: Icon(Icons.list)
),
Tab(
icon: Icon(Icons.map)
)
],
),
],
),
),
body: TabBarView(
children: <Widget>[
Container(
child: ListView(
children: <Widget>[
Container(
color: Colors.red,
height: 100,
child: Text('Hello'),
),
],
)
),
Container(
child: Text('testuju'),
)
],
),
),
);
Is it even possible to do it with Tab View, or should I fake tabs with styled buttons? Thanks a lot!
You can do it like this
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: PreferredSize(
child: AppBar(
backgroundColor: Colors.greenAccent,
bottom: TabBar(
controller: tabController,
tabs: [
Tab(
child: Text("Login"),
),
Tab(
child: Text("Sign Up"),
),
],
indicatorColor: Colors.black,
),
flexibleSpace: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.red,
Colors.orange,
],
),
),
),
),
preferredSize: Size.fromHeight(200.0),
),
body: TabBarView(
controller: tabController,
children: [
LoginApp(),
SignUpApp(),
],
),
),
);
you can try that:
Scaffold(
body: DefaultTabController(
initialIndex: // initial tab,
length: // tabs numbers,
child: NestedScrollView(
headerSliverBuilder: (buildContext, isScrolled){
return <Widget>[
SliverAppBar(
floating: false,
pinned: true,
primary: true,
automaticallyImplyLeading: false,
actions: <Widget>[
BackBtnIcon(action: (){
Navigator.pop(context);
},
),
SizedBox(width: 6,),
],
title: Text(memberFullName),
),
SliverPadding(
padding: EdgeInsets.all(0),
sliver: SliverList(
delegate: SliverChildListDelegate(
[
Container(
color: CopticColors.mainButtonColor,
child: CustomTabBar()
),
]
)
),
)
];
},
body: SafeArea(
minimum: EdgeInsets.all(20),
child: TabBarView(
// physics: new NeverScrollableScrollPhysics(),
children: [ // replace with your tabs
ConfessionTab(model: snapshot.data,),
CommunicationDetails(model: snapshot.data,),
GeneralDetails(model: snapshot.data,),
ChurchDetails(model: snapshot.data,),
GovDetails(model: snapshot.data,),
],
)
)
),
);