At my mobile apps homepage i have tabbar with two tabs act as category. both of those tabs display a listview with content depends on the category. (for example, a listview of book with fiction and non-fiction category.) and i want to add a single search function to search a book regardless their category.
The problem is:
One search bar can only search on one category. means the search bar can only search on fiction category. i try to add 2nd search bar in each tab but in result it act like the problem below
that whenever i click on the 2nd tab and then click on search bar, it will automatically go back to first tabs which is the default tab.
Solution that i think of:
Is to add setState so the tabs doesnt move back to default tab whenever i click on the search bar, but i dont know how.
Here is my code:
// Tab Bar MOF and CIDB
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(16),
bottomRight: Radius.circular(16)
),
color: Theme.of(context).primaryColor,
),
width: double.infinity,
child: TabBar(
controller: _tabController,
indicatorSize: TabBarIndicatorSize.tab,
indicatorPadding: EdgeInsets.all(6),
indicator: const UnderlineTabIndicator(borderSide: BorderSide(color: Colors.red, width: 100.0),
insets: EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 42.0),
),
unselectedLabelColor: Colors.grey,
tabs: [
Tab(child: Text('MOF', style: TextStyle(fontSize: 20, fontWeight: FontWeight.w300, ))),
Tab(child: Text('CIDB', style: TextStyle(fontSize: 20, fontWeight: FontWeight.w300)))
]
),
),
SizedBox(
height: 30,
),
//Space for Tender Listview
Expanded(
child: Container(
width: double.infinity,
//Tender List tile
child: TabBarView(
controller: _tabController,
children: [
//MOF List
Column(
children: [
Expanded(
child: ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: MOFs.length,
itemBuilder: (context, index) {
final MOF = MOFs[index];
return Card(
margin: EdgeInsets.fromLTRB(15, 20, 15, 20),
child: InkWell(
onTap: (){},
child: Container(
margin: EdgeInsets.all(4),
height: 200,
decoration: BoxDecoration(borderRadius: BorderRadius.circular(12),
//color: Colors.blue
),
child: Center(child: Text(MOF.title)),
),
),
);
}),
),
Container(
//color: Colors.pink,
margin: EdgeInsets.fromLTRB(150, 10, 150, 10),
child: TextField(
controller: controller,
onChanged: searchMOF,
decoration: InputDecoration(
hintText: 'Search by Keyword',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: BorderSide(color: Colors.green))
),
),
),
],
),
//CIDB List
Column(
children: [
Expanded(
child: ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: CIDBs.length,
itemBuilder: (context, index) {
final CIDB = CIDBs[index];
return Container(
margin: EdgeInsets.all(10),
height: 200,
width: 50,
decoration: BoxDecoration(borderRadius: BorderRadius.circular(20),
//color: Colors.purple
),
child: InkWell(
onTap: (){},
child: Card
(child: Center(child: Text(CIDB.title))),
),
//List testing
);
}),
),
Container(
//color: Colors.pink,
margin: EdgeInsets.fromLTRB(150, 10, 150, 10),
child: TextField(
controller: controller,
onChanged: searchCIDB,
decoration: InputDecoration(
hintText: 'Search by Keyword',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: BorderSide(color: Colors.green))
),
),
),
],
),
],
),
),
),
],
),
);
}
CodePudding user response:
You can make the search bar works globally by creating a parent stateful widget with search bar and child widget with tabs and tabs' body. In each tab body, you can check if search text field controller is not empty and if yes, you make only the books that contains search text appears and if no, you make the whole list appears
CodePudding user response:
the whole step is too wide. i'll suggest some outline.
- first of all, you have to know behaviour of
ListView
in flutter: Creation and Destruction
Only visible children will be rendered in a listview. When a child is scrolled out of view, the associated element subtree, states and render objects are destroyed
- second is the lifecycle. When you call
setState
it means flutter re-executebuild
method. the method below.
@override
Widget build(BuildContext context) {
return
thats why, everytime you call setState, the tabs is back to first tab. because it execute build
method from the begining.
- how to avoid rebuild entire widget is: Separate into new class. eg:
class TabMOF extend StatelessWidget{
...
@override
Widget build(BuildContext context) {
return your MOF list
...
class TabCIBD extend StatelessWidget{
...
@override
Widget build(BuildContext context) {
return your CIBD list
then use is as a widget in your main Screen
...
body : Column(
children: [
// here will be your search bar
...
// next is your tabbar
Container(
child: TabBar(
tabs: [tab1, tab2 ]
)
Expanded(
child: TabBarView(
children:[
TabMOF(),
TabCIBD(),
]
]
with this way, your tab will not rebuild. but you have to update the List data for each tab. if you need to rebuild your stateFullwidget tab, you can change the valuekey. article
actually its hard to explain very detail, hope you got what i mean. thank you