My question is about the difference between TabBar and TabBarView.
I can't tell any difference in looks, but what are the functions of both of them?
TabBar is used to create the tabs themselves, while TabBarView is used to create each bar content.
Look at the example in the docs
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: TabBarView(
children: [
Icon(Icons.directions_car),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
],
),
),
),
);
}
}
From the image the TabBar is the bottom of the blue bar (AppBar), and the TabBar view is the white page under the bar. Also the whole application is wrapped with DefaultTabController
Related
Let's say I have a Bottom Nav Bar as below, and I have used Navigator.pushNamed in in viewing those screens through onClick.
What I want to know is rather than having the Navigator.pushNamed on each of the button clicks in the NavBar buttons to navigate through the pages, is there a technique that can be used before executing the Navigator.pushNamed command to see whether there is an instance of the screen already created in the stack so that I can use the Navigator.popUntil method to have better performance.
You can use Tabbar widget in bottom navigation bar. I hope it will solve your current concerns.
import 'package:flutter/material.dart';
void main() {
runApp(const TabBarDemo());
}
class TabBarDemo extends StatelessWidget {
const TabBarDemo({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
title: const Text('Tabs Demo'),
),
bottomNavigationBar: const TabBar(
tabs: [
Tab(icon: Icon(Icons.directions_car, color: Colors.black)),
Tab(icon: Icon(Icons.directions_transit, color: Colors.black)),
Tab(icon: Icon(Icons.directions_bike, color: Colors.black)),
],
),
body: const TabBarView(
children: [
Icon(Icons.directions_car),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
],
),
),
),
);
}
}
One of App Screen need swipable tabs , so i just wanna implement default controller by the way, the official syntax is :
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)),
],
),
),
),
);
Now, In my project the main.dart file holds routes and materialapp widget , it seems like
Widget build(BuildContext context) {
return MaterialApp(
title: '....',
theme: ThemeData(....),
home: LoginScreen(),
initialRoute: '/LoginScreen',
routes: {
'/HomeScreen': (context) => HomeScreen(),
'/LoginScreen': (context) => LoginScreen(),
'/MatchesScreen': (context) => MatchesScreen(),//this is the screen i want to implement tabs
....
//other routes
});
}
In Matches Screen(tabs screen) it will return Scaffold
class _MatchesScreenState extends State<MatchesScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
//it only holds app bar and other stuff
);
}
}
here i could not use home property because home is the property of MaterialApp(), my question is how can i use tabs in this scenario , is there any way to replace the home property or override it. help me to resolve this problem
You can use body property instead of home
return 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('Flutter Tabs Example'),
),
body: TabBarView(
children: [
MatchesScreen(),
Text('second'),
Text('third')
],
),
)
);
But there are three TabBars, and if one TabBarView is MatchesScreen, then what are the two remaining TabBarView ?
i have been trying lots of solutions on changing appbar title with tabs, and i solved it but now there is a small problem; the appbar does change with the tabs when the tabs are pressed, but not the tabbarview. Swiping left or right on the tab bar view changes the tabbarview but not the tabs(appbar title does not change too).
my code below:
final List<Tabs> _tabs = [new Tabs(title: "Registered UAS", icon: new IconData(58826, fontFamily: 'MaterialIcons')),
new Tabs(title: "Registration", icon: IconData(57680, fontFamily: 'MaterialIcons'))
];
Tabs _myHandler ;
void initState() {
super.initState();
_controller = new TabController(length: 2, vsync: this);
_myHandler = _tabs[0];
_controller.addListener(_handleSelected);
}
void _handleSelected() {
setState(() {
_myHandler= _tabs[_controller.index];
});
}
#override
Widget build(BuildContext context) {
return WillPopScope(
child: DefaultTabController(
length: 2,
child: new Scaffold(
appBar: AppBar(
title: Text(_myHandler.title),
bottom: new TabBar(
controller: _controller,
tabs: <Widget>[
new Tab(icon: new Icon(_tabs[0].icon)),
new Tab(icon: new Icon(_tabs[1].icon))
],
),
),
body: new TabBarView(children: [...])
I followed this for changing appbar title on tab change and now im stuck with a similar situation like this, except i dont think the solution for it works for me(i have tried it)
solved it by adding controller: _controller, under TabBarView
If you want to use own controller, then you shouldn't use DefaultTabControllerwidget. In example, which you use DefaultTabController is absent.
If you want to use own controller you should use this example.
https://api.flutter.dev/flutter/material/TabController-class.html
If you want to use DefaultTabController without own controller, you should this example.
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: TabBarView(
children: [
Icon(Icons.directions_car),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
],
),
),
),
);
}
}
I followed the tutorial ( https://flutter.dev/docs/cookbook/design/tabs ) on how to create a flutter tabbar, if I wanted the user to add / remove tabs, how can I do it dynamically ?
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: TabBarView(
children: [
Icon(Icons.directions_car),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
],
),
),
),
);
}
}
When I create a tab the scroll must point to the new generated item
When I delete a tab the scroll must point to the previous element
First of all you need to convert your Stateless widget to a stateful widget. Then set the icons as a variable list.
class TabBarDemoState extends State<TabBarDemo> {
var icons = List<Icon>();
initState() {
super.initState();
icons = [
Icon(Icons.directions_car),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
];
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
tabs: icons,
),
title: Text('Tabs Demo'),
),
body: TabBarView(
children: icons,
),
),
),
);
}
}
Now say you want to remove an icon from the list. Write a method callback for it, for example a button press. Call this method when the button press or when an event occurs. Something like this:
class TabBarDemoState extends State<TabBarDemo> {
var icons = List<Icon>();
initState() {
super.initState();
icons = [
Icon(Icons.directions_car),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
];
}
void removeAnIcon() {
if (icons.isNotEmpty) {
setState({
icons.removeAt(0);
});
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
tabs: icons,
),
title: InkWell(
onTap: () => removeAnIcon(),
Text('Tabs Demo')
),
),
body: TabBarView(
children: icons,
),
),
),
);
}
}
When you call setState then the build function is called again and widget tree is rebuilt. Therefore, when you press on the title then you will remove one icon and get one less icon. Read more about Stateful widgets here
I have a TabBarView which contains a List of items, and I assign a Navigator.push method for each item. Currently this method will jump to a new page.
My question is , is it possible to navigate to the new page inside the body of the TabBarView? Which means I would like to navigate to another page while keeping all my top app bar and BottomNavigationBar on the screen.
Yes, you need to put your TabBarView inside a TabController:
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: TabBarView(
children: [
Icon(Icons.directions_car),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
],
),
),
),
);
}
}
Taken from https://flutter.io/docs/cookbook/design/tabs