So in here i want to change some condition if my tabview switch to the second tab but i don't know how to get the tabbar index, already try this and that. Im hoping some solution without statefull, Im using GetX thanks.
im planning to change the extendBody: true, in my main page to false when the tab switch to the second tab i had the logic for that hopefully but the only problem is the index :(.
My tabs :
List<Tab> myTabs = [
Tab(
text: 'Following',
),
Tab(
text: 'Trending',
),
Tab(
text: 'Search',
),
];
DefaultController code :
DefaultTabController(
length: myTabs.length,
child: Scaffold(
extendBodyBehindAppBar: true,
backgroundColor: bgColor,
// APPBAR
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
toolbarHeight: 60,
// BOTTOM
bottom: PreferredSize(
preferredSize: const Size.fromHeight(0),
child: Align(
alignment: Alignment.centerLeft,
child: TabBar(
isScrollable: true,
labelPadding: EdgeInsets.only(left: 20),
labelColor: Colors.white,
labelStyle: poppins.copyWith(
fontSize: 15,
fontWeight: bold,
),
unselectedLabelColor: Color(0xff585861),
indicatorColor: Colors.white.withOpacity(0),
indicatorSize: TabBarIndicatorSize.label,
// TABS
tabs: myTabs,
),
),
),
),
body: TabBarView(
children: [
FollowingTab(),
TrendingTab(),
search(),
],
),
),
);
Use TabBar with TabController and you can find current index while switching to next tab
#override
void initState() {
super.initState();
_controller = TabController(length: 6, vsync: this);
_controller!.addListener(() {
print(_controller!.index);
});
}
your build method be like:
#override
Widget build(BuildContext context) {
return Scaffold(
bottom:TabBar(
controller: _controller,
tabs:[
//your tabs will be here
]
),
body:TabBarView(
controller: _controller,
children: [
//your tabbarview will be here
]
),
);
}
Here i just code of Tabbar with using Getx and Stateless Widget.
CheckOut my code and if you find solution then give up me. Thanks in advance
class TabDemo extends StatelessWidget {
TabDemo({Key? key}) : super(key: key);
final DemoController demoController = Get.put(DemoController());
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
bottom: const TabBar(
tabs: [
Tab(icon: Icon(Icons.flight)),
Tab(icon: Icon(Icons.directions_transit)),
Tab(icon: Icon(Icons.directions_car)),
],
),
title: const Text('Tabs Demo'),
),
body: TabBarView(
controller: demoController.controller?.value,
children: const [
Icon(Icons.flight, size: 350),
Icon(Icons.directions_transit, size: 350),
Icon(Icons.directions_car, size: 350),
],
),
),
);
}
}
You need to create controller class to define controller and initmethod
class DemoController extends GetxController with SingleGetTickerProviderMixin {
Rx<TabController>? controller;
#override
void onInit() {
// TODO: implement onInit
controller?.value = TabController(length: 6, vsync: this);
controller?.value.addListener(() {
print(controller?.value.index);
});
super.onInit();
}
}
Related
I use a default Tabbar. I have two tab .When I change tabview by clicking, onTab method call finely. But when I change tabview by swiping or scrolling, how I can call onTab method?. How I can listen my onTab changing value when I change my tabview by swiping or scrolling? I need change tabIndex value in controller when I change tabView by swiping or scroling.
UI Part here
#override
Widget build(BuildContext context) {
return DefaultTabController(
initialIndex: 0,
length: 2,
child: Scaffold(
appBar: AppBar(
backgroundColor: AllColors.deepPurple,
leading: InkWell(
onTap: () => Get.back(),
child: Icon(
Icons.arrow_back,
color: AllColors.whiteColor,
),
),
elevation: 0.0,
title: Text(
"Categories",
style: AllStyles.titleTextStyle,
),
actions: [
InkWell(
child: Padding(
padding: const EdgeInsets.only(right: 12.0),
child: Icon(Icons.add),
),
onTap: () {
},
)
],
bottom: TabBar(
controller: categoriesController.tabController,
onTap: (value) {
categoriesController.changeTabValue(value);
print("Value " + value.toString());
},
isScrollable: false,
indicatorColor: AllColors.whiteColor,
indicatorSize: TabBarIndicatorSize.label,
tabs: [Tab(text: "Income"), Tab(text: "Expense")],
),
),
body: TabBarView(
children: [
IncoomeTabCategories(),
ExpenseTabCategories()
],
),
),
);
}
Controller part here:
class CategoriesController extends GetxController with GetSingleTickerProviderStateMixin {
TabController? tabController;
int tabIndex=0;
#override
void onInit() {
super.onInit();
tabController = TabController(length: 2, vsync: this,initialIndex: 0)
}
#override
void dispose() {
super.dispose();
tabController!.dispose();
}
void changeTabValue(int index){
tabIndex=index;
update();
}
}
I am using hooks for handling tab controller, the problem is when i print the current index of the controller it is right. But when i try to display it inside a text widget it is never changes! how could i use it?
The code is:
class TabBarDemo extends HookWidget {
final List<Widget> list = const [
Tab(icon: Icon(Icons.card_travel)),
Tab(icon: Icon(Icons.add_shopping_cart)),
Tab(icon: Icon(Icons.ac_unit)),
];
#override
Widget build(BuildContext context) {
final _controller =
useTabController(initialLength: list.length, initialIndex: 0);
_controller.addListener(() {
print("\n ${_controller.index} \n");
});
return Scaffold(
appBar: AppBar(
bottom: TabBar(
onTap: (index) {},
controller: _controller,
tabs: list,
),
),
body: TabBarView(
controller: _controller,
children: [
Center(
child: Text(
'${_controller.index}',
)),
Center(
child: Text(
'${_controller.index}',
)),
Center(
child: Text(
'${_controller.index}',
)),
],
),
);
}
}
You have to rebuild the tree using :
setState(() {
});
I have created a TabBar inside my AppBar with the code below. I'm curious if I can use this TabBar as a filtering mechanism like the image below. I feel like there might already be a widget available for this, but I can't find any evidence of that. If I do have to use the TabBar, how would I go about toggling each option and filtering based on this list of toggles.
Current code:
import 'package:flutter/material.dart';
class ExploreDetail extends StatefulWidget {
static const routeName = 'explore_detail';
#override
_ExploreDetailState createState() => _ExploreDetailState();
}
class _ExploreDetailState extends State<ExploreDetail>
with SingleTickerProviderStateMixin {
TabController _tabController;
List<Widget> tabs = [
Tab(
text: 'All',
),
Tab(
text: 'Experience Consulting',
),
Tab(
text: 'Front Office Transformation',
),
];
#override
void initState() {
// TODO: implement initState
super.initState();
// Create TabController for getting the index of current tab
_tabController = TabController(
length: tabs.length,
initialIndex: 0,
vsync: this,
);
}
#override
Widget build(BuildContext context) {
final Map category = ModalRoute.of(context).settings.arguments;
return Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(kTextTabBarHeight + kToolbarHeight),
child: AppBar(
title: Text(
category['title'],
style: TextStyle(color: Colors.black),
),
backgroundColor: Colors.white,
iconTheme: IconThemeData(
color: Colors.black,
),
bottom: PreferredSize(
preferredSize: Size.fromHeight(kTextTabBarHeight),
child: Align(
alignment: Alignment.centerLeft,
child: TabBar(
tabs: tabs,
controller: _tabController,
indicatorColor: Colors.transparent,
labelColor: Colors.blue,
isScrollable: true,
unselectedLabelColor: Colors.grey,
),
),
),
),
),
body: Center(
child: Text('list of cards will go here'),
),
);
}
}
You can handle the tab selections by adding an addListener method to your tabController in your initState(). And then you can filter your data by the selected tab option.
It will look like:
#override
void initState() {
// TODO: implement initState
super.initState();
// Create TabController for getting the index of current tab
_tabController = TabController(
length: tabs.length,
initialIndex: 0,
vsync: this,
);
// Here is the addListener!
_tabController.addListener(_handleTabSelection);
}
And then:
void _handleTabSelection() {
if (_tabController.indexIsChanging) {
switch (_tabController.index) {
case 0:
filterData('all');
break;
case 1:
filterData('experienceConsulting');
break;
case 2:
filterData('frontOfficeTransformation');
break;
}
}
}
I just learned flutter, I was confused how to use the TabController, I had followed what was described on the official website, but an error appeared, and I don't know how to fix it.
I just want to change the title and leading from the appbar when changing tabs.
final List<ChangeTitleAndLeading> _data = [
new ChangeTitleAndLeading(title: "Home", leading: Icon(Icons.home)),
new ChangeTitleAndLeading(title: "Profile", leading: Icon(Icons.person)),
new ChangeTitleAndLeading(title: "Friends", leading: Icon(Icons.people))
];
ChangeTitleAndLeading _handler;
TabController _controller;
#override
void initState() {
super.initState();
_checkEmailVerification();
_controller = TabController(vsync: this, length: 3);
_handler = _data[0];
_controller.addListener(_handleSelected);
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
void _handleSelected() {
setState(() {
_handler = _data[_controller.index];
});
}
return MaterialApp(
theme: new ThemeData(
primarySwatch: Colors.teal,
),
home: new Scaffold(
appBar: new AppBar(
leading: Icon(Icons.home),
title: new Text("Home"),
bottom: new TabBar(
controller: _controller,
tabs: _tabs,
),
),
body: TabBarView(
controller: _controller,
children: _pages,
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
print('Current Index: ${_handler.title}');
}
),
class ChangeTitleAndLeading {
final String title;
final Widget leading;
ChangeTitleAndLeading({
#required this.title,
#required this.leading
}) :
assert(title != null),
assert(leading != null);
}
Error log:
Error Log:
I/flutter (19638): No TabController for TabBarView.
I/flutter (19638): When creating a TabBarView, you must either provide an explicit TabController using the "controller"
I/flutter (19638): property or you must ensure that there is a DefaultTabController above the TabBarView.
I/flutter (19638): In this case, there was neither an explicit controller nor a default controller.
════════════════════════════════════════════════════════════════════════════════════════════════════
I/flutter (19638): Another exception was thrown: No TabController for TabBar.
And when i change this:
leading: Icon(Icons.home), to leading: _handler.leading,
and this:
title: new Text("Home"), to title: new Text(_handler.title),
always return error _handler.leading or _handler.title was null
Image
Try this solution :-
don't forget to inhert
TickerProviderStateMixin
class HomePage extends StatefulWidget {
const HomePage();
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
late TabController tabController;
#override
void initState() {
super.initState();
tabController = TabController(
initialIndex: 0,
length: 2,
vsync: this,
);
}
#override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Scaffold(
appBar: AppBar(
title: Row(
children: [
Image.asset(
'assets/images/png/logo.png',
height: 60,
width: 60,
),
Spacer(),
Container(
width: 400,
child: TabBar(
labelColor: Color.fromRGBO(4, 2, 46, 1),
labelStyle: theme.textTheme.headline1,
indicatorColor: Color.fromRGBO(4, 2, 46, 1),
unselectedLabelColor: Colors.grey,
controller: tabController,
tabs: [
Text('الفاتورة'),
Text('دليفري'),
],
),
),
],
),
),
body: Container(
child: TabBarView(
controller: tabController,
children: [
Container(
color: Colors.red,
),
Container(
color: Colors.orange,
),
],
),
),
);
}
#override
void dispose() {
tabController.dispose();
super.dispose();
}
}
The issue is that you are missing a tabbarcontroller
Your code should be:
return MaterialApp(
theme: new ThemeData(
primarySwatch: Colors.teal,
),
home: DefaultTabController(
length: 3,
child: new Scaffold(
appBar: new AppBar(
leading: Icon(Icons.home),
title: new Text("Home"),
bottom: new TabBar(
controller: _controller,
tabs: _tabs,
),
),
body: TabBarView(
controller: _controller,
children: _pages,
)...
I implemented a basic TabBar and TabBarView with a DefaultTabController, see code below.
class MyApp2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: BOTTOM_TABS,
child: Scaffold(
appBar: AppBar(title: const Text('Bottom App Bar')),
body: _tabBarView(),
bottomNavigationBar: _bottomTabBar(),
),
);
}
_tabBarView() {
return TabBarView(
physics: NeverScrollableScrollPhysics(),
children: [
Container(
color: Colors.blue,
),
Container(
color: Colors.orange,
),
Container(
color: Colors.lightGreen,
),
Container(
color: Colors.red,
),
],
);
}
_bottomTabBar() {
return TabBar(
tabs: [
Tab(
icon: new Icon(Icons.home),
),
Tab(
icon: new Icon(Icons.public),
),
Tab(
icon: new Icon(Icons.group),
),
Tab(
icon: new Icon(Icons.person),
)
],
);
}
}
Works great! Now what I want to do is change the animation between the two tabs from the default animation. But I can't find an easy way to do that.
After a bit of research it seems like I need to use a custom TabController and somehow use its animateTo method. To me that seems like a pretty big change just to change the animation. What I wonder is if that is the correct way or if I am missing some easier way to just change the default animation between the tabviews?
If someone could give me some good resources to point me in the right direction I'd greatly appreciate it.
This is not hard, just use TabController (to do so you need to use SingleTickerProviderStateMixin ) and AnimatedBuilder.
class MyApp2 extends StatefulWidget {
#override
_MyApp2State createState() => _MyApp2State();
}
class _MyApp2State extends State<MyApp2> with SingleTickerProviderStateMixin {
TabController _tabController;
#override
void initState() {
_tabController = TabController(length: 4, vsync: this);
super.initState();
}
_tabBarView() {
return AnimatedBuilder(
animation: _tabController.animation,
builder: (BuildContext context, snapshot) {
return Transform.rotate(
angle: _tabController.animation.value * pi,
child: [
Container(
color: Colors.blue,
),
Container(
color: Colors.orange,
),
Container(
color: Colors.lightGreen,
),
Container(
color: Colors.red,
),
][_tabController.animation.value.round()],
);
},
);
}
_bottomTabBar() {
return TabBar(
controller: _tabController,
labelColor: Colors.black,
tabs: [
Tab(
icon: new Icon(Icons.home),
),
Tab(
icon: new Icon(Icons.public),
),
Tab(
icon: new Icon(Icons.group),
),
Tab(
icon: new Icon(Icons.person),
)
],
);
}
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 4,
child: Scaffold(
appBar: AppBar(title: const Text('Bottom App Bar')),
body: _tabBarView(),
bottomNavigationBar: _bottomTabBar(),
),
);
}
}
Screenshot (Null safe):
Code:
If you want fine-grained control, you can make use of the AnimationController.
class _MyPageState extends State<MyPage> with TickerProviderStateMixin {
late final TabController _tabController;
late final AnimationController _controller;
#override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(milliseconds: 400),
value: 1,
);
_tabController = TabController(
length: 3,
vsync: this,
)..addListener(() {
if (_tabController.indexIsChanging) {
setState(() => _controller.forward(from: 0.5));
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ScaleTransition(
scale: _controller,
child: [
Container(color: Colors.red),
Container(color: Colors.green),
Container(color: Colors.blue),
][_tabController.index],
),
bottomNavigationBar: TabBar(
controller: _tabController,
tabs: [
Tab(child: Text('Red')),
Tab(child: Text('Green')),
Tab(child: Text('Blue')),
],
),
);
}
}
I don't know if you want to completely change the animation.
But if you just need some customization, did you try to use a TabController instead of a DefaultTabController ?
You just need to pass the tabController as an arg to the TabBar & TabBarView.
To customize the animation with the tabController, you should specify an Animation for the tabController and also specify the curve and duration with the animateTo function of the tabController.
https://api.flutter.dev/flutter/material/TabController/animateTo.html
https://api.flutter.dev/flutter/material/TabController-class.html
Disable animation between flutter tabs by setting animation duration to zero like this
tabController = TabController(
animationDuration: Duration.zero,
length: 4, vsync: this, initialIndex: 0);
Thank me later.