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
Related
I have this code that displays text and tabs. But I need an image instead of text. How can I replace the title text with an image?
void main() async {
runApp(Start());
}
class Start extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
//icon: Image.asset('assets/Title_image.png')
title: ('Title text'),
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: DefaultTabController(
length: 5,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
tabs: [
Tab(icon: Image.asset('assets/tabs/image1.png')),
Tab(icon: Image.asset('assets/tabs/image2.png')),
Tab(icon: Image.asset('assets/tabs/image3.png')),
Tab(icon: Image.asset('assets/tabs/image4.png')),
Tab(icon: Image.asset('assets/tabs/image5.png')),
],
),
title: Text('Title text'),
backgroundColor: Colors.blue,
),
body: TabBarView(
children: [
Icon(Icons.music_note),
Icon(Icons.music_video),
Icon(Icons.camera_alt),
Icon(Icons.grade),
Icon(Icons.email),
],
),
),
),
);
}
}
How do I change the "Title test" to an image? Interesting issues with the stackoverflow editor. There was a comment requesting the complete code. But when I included the complete code, I could not save the edit, it insists more details even though there aren't any. This is a cause of the failure of too much automation. It required extra irrelevant words to posy the complete code as requested in the comments.
The solution is to remove the title parameter passed to MaterialApp and pass an image to the title parameter of the AppBar.
void main() async {
runApp(Start());
}
class Start extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: DefaultTabController(
length: 5,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
tabs: [
Tab(icon: Image.asset('assets/tabs/image1.png')),
Tab(icon: Image.asset('assets/tabs/image2.png')),
Tab(icon: Image.asset('assets/tabs/image3.png')),
Tab(icon: Image.asset('assets/tabs/image4.png')),
Tab(icon: Image.asset('assets/tabs/image5.png')),
],
),
title: **Image.asset('assets/Title_image.png')**,
backgroundColor: Colors.blue,
),
body: TabBarView(
children: [
Icon(Icons.music_note),
Icon(Icons.music_video),
Icon(Icons.camera_alt),
Icon(Icons.grade),
Icon(Icons.email),
],
),
),
),
);
}
}
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),
],
),
),
),
);
}
}
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
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