I want to place a custom widget in place of appbar and want a tab view below it - flutter

I have built a custom widget("cab") which displays a account login circle and no. of points user have.
I want a tab view just below it . For now I have placed this custom widget inside the tab itself :
bottomNavigationBar: Material(child: TabBar(
tabs: const <Widget>[
Tab( icon: Icon(Icons.add)),
Tab( icon: Icon(Icons.search))
]
),),
body :TabBarView(
children: <Widget>[
Column(
children: <Widget>[
cab
],
),
But I want this widget to be displayed above tab view but not the part of tab view itself . How can I do
this?
Thanks.

Replace the AppBar widget with your own widget below:
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: DefaultTabController(
length: 2,
child: Scaffold(
bottomNavigationBar: TabBar(
labelColor: Colors.orange,
unselectedLabelColor: Colors.grey,
indicatorSize: TabBarIndicatorSize.tab,
indicatorColor: Colors.orange,
tabs: [
Tab(
icon: Icon(Icons.add),
),
Tab(
icon: Icon(Icons.search),
),
],
),
body: Column(
children: <Widget>[
// Remove the AppBar code below and put your "cab" widget
AppBar(
primary: true,
title: Text('Here is your cab'),
centerTitle: true,
backgroundColor: Colors.orange,
),
Expanded(
child: TabBarView(
children: [
Icon(Icons.add),
Icon(Icons.search),
],
),
),
],
),
),
),
);
}
}

Related

How to add multiple widgets to widget list

I am currently working on my first flutter app and still learning. I thought I kind of figured out how to combine and add multiple widgets. The tap Bar is actually working. When I add the tap bar in a Column it is not working anymore. I would like to add a Bottom Navigation Bar. It is also working without the TapBar. But both combined with the Column and Widget List are not working and I cant figure out why not.
Widget build(BuildContext context) {
return new Scaffold(
appBar: new TabBar(
controller: controller,
labelColor: Colors.white,
tabs: <Tab>[
new Tab(
icon: new Icon(
Icons.arrow_back,
color: Theme.of(context).primaryColor,
)),
new Tab(
icon: new Icon(
Icons.swap_calls,
color: Theme.of(context).primaryColor,
)),
new Tab(
icon: new Icon(
Icons.favorite,
color: Theme.of(context).primaryColor,
)),
]),
body: Column(
children: <Widget>[
new TabBarView(
controller: controller,
children: <Widget>[
new first.Outfits(),
new second.Swaps(),
new third.Favorites()
],
),
//BottomNavigationBar
/* new BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text('Home'),
),
BottomNavigationBarItem(
icon: Icon(Icons.people),
title: Text('Friends'),
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
title: Text('Profile'),
),
],
// currentIndex: _selectedIndex,
// onTap: _onItemTab,
),*/
// ],
//),
],
),
);
}```
Does anybody know what might be the reason ? Maybe it is the other Widgetlist in my TabBar Widget ?
Thank you!
As you already used Scaffold just use it's bottomNavigationBar
Straightforward settle BottomNavigationBar in bottomNavigationBar property
The [bottomNavigationBar] is rendered below the [persistentFooterButtons]
and the [body].
It's simple, wrap your TabBarView inside Expanded widget to use it into the Column
Column(
children: <Widget>[
Expanded(
child: new TabBarView(
controller: controller,
children: <Widget>[
Text('Hi 1'),
Text('Hi 2'),
Text('Hi 3'),
],
),
),
],
),

How do I override a Flutter TabBar Tab to work as a FloatingActionButton?

I'm trying to achieve this functionality:
When I press the last Tab button, I don't want to change to any view. I just want to show those two buttons, no matter which view I'm on.
I've tried with this solution, but it hasn't helped.
This is my code so far
class MainViewState extends State<MainView> {
var tabsList = [
Tab1View(),
Tab2View(),
Tab3View(),
Tab4View()
];
#override
Widget build(BuildContext context) {
return ViewModelProvider<MainViewModel>.withConsumer(
viewModel: MainViewModel(),
builder: (context, viewModel, child) => DefaultTabController(
length: tabsList.length,
child: Scaffold(
drawer: mainViewDrawerHeader(context),
appBar: AppBar(
title: Text('Sample Text'),
centerTitle: true,
),
body: TabBarView(children: tabsList),
bottomNavigationBar: TabBar(
labelPadding: EdgeInsets.symmetric(horizontal: 0.0),
labelStyle:
TextStyle(fontSize: 14.5, fontWeight: FontWeight.bold),
unselectedLabelStyle: TextStyle(fontSize: 12.0),
tabs: <Widget>[
Tab(
icon: Icon(Icons.monetization_on),
text: 'Tab 1',
),
Tab(
icon: Icon(Icons.monetization_on),
text: 'Tab 2',
),
Tab(
icon: Icon(Icons.credit_card),
text: 'Tab 3',
),
Tab(
icon: Icon(Icons.phone),
text: 'Tab 4',
),
],
labelColor: Colors.red,
unselectedLabelColor: Colors.grey,
indicatorSize: TabBarIndicatorSize.tab,
indicatorColor: Colors.red,
onTap: (_) => {},
))));
}
}
Yes, one simple way to go about it is to use the Visibility widget.
Just wrap your column that contains the buttons in a visibility widget.
For example
bool isClicked = false;
Visibility(
visible: isClicked,
child: Column(
children : [
Icon(Icons.phone),
Icon(Icons.user),
],
)
),
Now in your Fab item do the following :
FabItem(
"Contacto",
Icons.phone,
onPress: () {
_controller.reverse();
sisClicked = true;
},
),
For more on visibility widget.

I am having an error with Flutter saying: Controller's length property does not match

I have been having this issue in Flutter when I am trying to use the DefaultTabController() widget but it seems it does not work the way I have specified the layout. Can anyone help me with it.
This is my code:
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 3,
initialIndex: 0,
child: Scaffold(
appBar: AppBar(
leading: IconButton(icon: Icon(Icons.menu), onPressed: () {}),
title: Text('Home'),
bottom: TabBar(tabs: [
Tab(child: Text("Videos")),
Tab(child: Text("Live Videos")),
Tab(child: Text("Gallery")),
]),
),
body: TabBarView(
children: [
new Card(
color: Colors.blue,
),
],
),
));
}
}
What am I doing wrong here?
Your body element only contains one element. According to your length attribute of the DefaultTabController, there should be 3 elements in that array.
body: TabBarView(
children: [
new Card(
color: Colors.blue,
),
new Card(
color: Colors.red,
),
new Card(
color: Colors.orange,
),
],
),

Adding tabs on clicking button

How can I add a new tab in TabBar by clicking on a button?
I tried to call 'setState' in order to add a new tab.
class _MyHomeState extends State<MyHome> {
final List<Tab> _tabs = [
Tab(
child: Text("tab 1"),
),
Tab(
child: Text("tab 2"),
)
];
int _length = 2;
final List<Widget> _tabBarView = [
Icon(Icons.ac_unit),
Icon(Icons.access_alarm)
];
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: _length,
child: Scaffold(
appBar: AppBar(
title: Text("New"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: () {
setState(() {
_tabs.add(
Tab(
child: Text("another"),
),
);
_tabBarView.add(
Icon(Icons.access_alarms),
);
_length = _tabs.length;
});
},
),
],
bottom: TabBar(
tabs: _tabs,
),
),
body: TabBarView(
children: _tabBarView,
),
),
);
}
}
By doing so, got an error message,
RangeError (index): Invalid value: Not in range 0..1, inclusive: 2
You need minor tweaking in your code:
change:
bottom: TabBar(
tabs: _tabs,
),
),
body: TabBarView(
children: _tabBarView,
),
to
bottom: TabBar(
tabs: _tabs.toList(), // Creates a [List] containing the elements of this [Iterable].
),
),
body: TabBarView(
children: _tabBarView.toList(), // Creates a [List] containing the elements of this [Iterable].
),

Use AppBar Style on a TabBar that is not its child

I want my tab bar to have the same styling as the AppBar.
(using the same icon color, text color and background color)
My layout features a tabbed section to the left and another column to the right. Whithout additional styling the TabBar icons are not visible because both they and the background are white.
So what would be the most convinient way to apply the AppBar style to the TabBar? Thanks for any suggestions!
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() => MyAppState();
}
class MyAppState extends State<MyApp> with TickerProviderStateMixin {
TabController _tabController;
#override
void initState() {
super.initState();
_tabController = TabController(
vsync: this,
length: 3,
initialIndex: 0,
);
}
#override
Widget build(BuildContext context) {
double bigSize = IconTheme.of(context).size * 4.0;
return MaterialApp(
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('Flutter TabBar Style Problem'),
),
body: Row(
children: <Widget>[
Expanded(
child: Column(
children: [
SizedBox(
height: 36.0,
child: TabBar(
controller: _tabController,
tabs: [
Tab(icon: Icon(Icons.cake)),
Tab(icon: Icon(Icons.train)),
Tab(icon: Icon(Icons.info)),
],
),
),
Flexible(
child: TabBarView(
controller: _tabController,
children: [
Icon(Icons.cake, size: bigSize),
Icon(Icons.train, size: bigSize),
Icon(Icons.info, size: bigSize),
],
),
),
],
),
),
Expanded(
child: Container(
color: Colors.amber.shade400,
alignment: FractionalOffset.center,
child: Text('Another Column'),
),
),
],
),
),
);
}
}
When you place a TabBar as the bottom: widget of the AppBar you get a lot of things for free. It gets the background color and a Material widget that has a special feature. It forces the indicator to use white color when the default indicator color is the same as the background color (give a look here).
So when you place a TabBar outside the AppBar you have to handle everything yourself.
But it seems pretty easy wrapping the TabBar in a Material and giving it the primaryColor (the same the framework does here).
So at the end is just replacing your SizedBox by a Material and setting the color. And you get the ink splash for free.
Material(
color: Theme.of(context).primaryColor,
child: TabBar(
controller: _tabController,
tabs: [
Tab(icon: Icon(Icons.cake)),
Tab(icon: Icon(Icons.train)),
Tab(icon: Icon(Icons.info)),
],
),
),
What appBar interally do is inserting a custom DefaultTextStyle that points to Theme.textTheme.title
You can do the exact same thing by wrapping a part of your widget tree into a custom DefaultTextStyle.
DefaultTextStyle(
style: Theme.of(context).textTheme.title,
child: Text('Title')
);
As for the background color, it is availble in another field of Theme.
Container(
color: Theme.of(context).primaryColor,
);
Change Your Code to Something Like This:
class ProductsAdminPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
// Scaffold is inside DefaultTabController because DefaultTabController needs access to Scaffold
return DefaultTabController(
// Number of tabs
length: 2,
child: Scaffold(
drawer: Drawer(
child: Column(
children: <Widget>[
AppBar(
automaticallyImplyLeading: false,
title: Text('Choose'),
),
ListTile(
title: Text('All Products'),
onTap: () {
Navigator.pushReplacement(context, MaterialPageRoute(builder: (BuildContext context) => ProductsPage()));
},
)
],
),
),
appBar: AppBar(
title: Text('Manage Products'),
// TabBar is added as the bottom widget of the appBar
bottom: TabBar(
tabs: <Widget>[
// No of Tab() Widgets Should be equal to length
Tab(
icon: Icon(Icons.create),
text: 'Create Product',
),
Tab(
icon: Icon(Icons.list),
text: 'My Products',
),
],
),
),
body: TabBarView(
// No of pages should be equal to length
children: <Widget>[ProductCreatePage(), ProductListPage()],
),
),
);
}
}
ThemeData(
appBarTheme: AppBarTheme(
...
),
tabBarTheme: TabBarTheme(
labelColor: Colors.black,
unselectedLabelColor: Colors.grey,
indicatorSize: TabBarIndicatorSize.label,
labelStyle: TextStyle(
fontSize: 20.0,
color: Colors.green,
),
unselectedLabelStyle: TextStyle(
fontSize: 20.0,
color: Colors.green,
),
),
);
We can customise theme in App Level theme as our app bar and then every where in app, tabs will use same style as we define in theme.
I hope it is the easiest approach...