I have a Scaffold, within it I have a TabBar, TabBarView and a TextField.
The TabBar has 3 tabs (e.g. tabs A, B and C), the TabBarView has 3 views and this TextField is at the last tab (tab C).
Everything is working, but whenever I put the focus on the TextField to type something, the TabBar is changed from tab C to tab A. Very annoying. This should not happen. The TabBarView remains unchanged.
I created the controller in the initState. like this:
#override
void initState() {
super.initState();
widget._tabBarController =
new TabController(length: 3, vsync: this);
}
Any idea why it happens?
Code:
class AtendimentoOrtoWidget extends StatefulWidget {
TabController _tabBarController;
#override
_AtendimentoOrtoWidgetState createState() => _AtendimentoOrtoWidgetState();
}
class _AtendimentoOrtoWidgetState extends State<AtendimentoOrtoWidget>
with SingleTickerProviderStateMixin {
#override
void initState() {
super.initState();
widget._tabBarController =
new TabController(length: 3, vsync: this);
}
#override
Widget build(BuildContext context) {
return SafeArea(
top: false,
child: new DefaultTabController(
length: 3,
child: new Scaffold(
resizeToAvoidBottomPadding: false,
appBar: new AppBar(
toolbarOpacity: 0.5,
automaticallyImplyLeading: true,
backgroundColor: Colors.white,
elevation: 2.0,
title: new TabBar(
controller: widget._tabBarController,
unselectedLabelColor: Colors.black,
indicatorColor: Colors.black,
labelColor: Colors.black,
// indicatorWeight: 0.0,
isScrollable: true,
labelStyle: new TextStyle(
fontSize: 16.0,
fontFamily: 'Caecilia',
fontWeight: FontWeight.w700),
tabs: <Widget>[
new Tab(
text: "TAB A",
),
new Tab(
text: "TAB B",
),
new Tab(
text: "TAB C",
)
],
),
),
backgroundColor: Colors.white,
body: new TabBarView(
controller: widget._tabBarController,
children: <Widget>[
new Container(),
new Container(),
new TextField()
],
))));
}
}
I tried it. Check the below code. If you still facing the same issue then share your implementation.
import 'package:flutter/material.dart';
class TabScreen extends StatefulWidget {
#override
_TabScreenState createState() => _TabScreenState();
}
class _TabScreenState extends State<TabScreen> with SingleTickerProviderStateMixin {
GlobalKey<ScaffoldState> _scaffoldKey = new GlobalObjectKey<ScaffoldState>('TabScreen');
TabController tabController;
#override
void initState() {
super.initState();
tabController = new TabController(length: 3, vsync: this);
}
#override
void dispose() {
super.dispose();
tabController.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: Text("Tab Demo"),
),
backgroundColor: Colors.white,
body: Column(
children: <Widget>[
TabBar(
controller: tabController,
tabs: <Widget>[
Tab(
child: Container(
child: new Text(
'A',
style: TextStyle(color: Colors.black),
),
),
),
Tab(
child: Container(
child: Text(
'B',
style: TextStyle(color: Colors.black),
),
),
),
Tab(
child: Container(
child: Text(
'C',
style: TextStyle(color: Colors.black),
),
),
)
],
),
Flexible(
child: TabBarView(
controller: tabController,
children: <Widget>[
Placeholder(),
Placeholder(),
ListView(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
decoration: InputDecoration(labelText: "Name"),
),
),
],
),
],
))
],
),
);
}
}
Related
Default the Tabar Tab width are equal.
How i can change each tabbar tab width differently ?
I tried this but not work
TabBar(
controller: _navController,
tabs: [
Expanded(
flex: 30,
child: IconButton(
icon: SvgPicture.asset("assets/svg/home.svg",height: height * .02,),
onPressed: () { },
)),
Expanded(
flex: 40,
child: Center(
child: IconButton(
icon: SvgPicture.asset("assets/svg/user.svg",height: height * .02,),
onPressed: () { },
),
)),
Expanded(
flex: 20,
child: Center(
child: IconButton(
icon: SvgPicture.asset("assets/svg/settings.svg",height: height * .02,),
onPressed: () { },
),
)),
Expanded(
flex: 10,
child: Container()),
],
),
Expecting Result
To have different sizes in tab bar you have to add isScrollable: true. Please try this example
class MyTabbedPage extends StatefulWidget {
const MyTabbedPage({Key? key}) : super(key: key);
#override
State<MyTabbedPage> createState() => _MyTabbedPageState();
}
class _MyTabbedPageState extends State<MyTabbedPage>
with SingleTickerProviderStateMixin {
List<Widget> myTabs = [
SizedBox(
width: 20.0,
child: Tab(text: 'hello'),
),
SizedBox(
width: 70,
child: Tab(text: 'world'),
),
];
late TabController _tabController;
#override
void initState() {
super.initState();
_tabController = TabController(vsync: this, length: myTabs.length);
}
#override
void dispose() {
_tabController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
bottom: TabBar(
controller: _tabController,
tabs: myTabs,
isScrollable: true,
),
),
body: TabBarView(
controller: _tabController,
children: myTabs.map((Widget tab) {
final String label = "Test";
return Center(
child: Text(
'This is the $label tab',
style: const TextStyle(fontSize: 36),
),
);
}).toList(),
),
);
}
}
I create Tab Bar for my project. It includes two tabs and these each tabs are represent two pages.
Here is the code
import 'package:flutter/material.dart';
class TabView extends StatefulWidget {
#override
_TabViewState createState() => _TabViewState();
}
class _TabViewState extends State<TabView> with SingleTickerProviderStateMixin {
TabController _tabController;
#override
void initState() {
_tabController = TabController(length: 2, vsync: this);
super.initState();
}
#override
void dispose() {
super.dispose();
_tabController.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey.shade300,
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Container(
height: 45,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(
16.0,
),
),
child: TabBar(
controller: _tabController,
indicator: BoxDecoration(
borderRadius: BorderRadius.circular(
16.0,
),
color: Colors.grey.shade900,
),
labelColor: Colors.white,
unselectedLabelColor: Colors.grey.shade900,
tabs: [
Tab(
text: 'One',
),
Tab(
text: 'Two',
),
],
),
),
Expanded(
child: TabBarView(
controller: _tabController,
children: [
Center(
child: Text(
'Page One',
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.w600,
),
),
),
Center(
child: Text(
'Page Two',
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.w600,
),
),
),
],
),
),
],
),
),
),
);
}
}
Here is output
I want to use the tab bar for a single page to change a widget state.
Example
I want use the tab bar to change the color of the container in page one from red to blue and I don't want to switch to page two
How can I do it?
TabBar is not quite suitable for this purpose, although it can be adapted. I suggest you to use CupertinoSegmentedControl from cupertino package. Here is docs, and here is code example:
enum _Tab { one, two }
class MyWidget extends StatefulWidget {
#override
State<StatefulWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
_Tab _selectedTab = _Tab.one;
#override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SizedBox(height: 16),
CupertinoSegmentedControl<_Tab>(
selectedColor: Colors.black,
borderColor: Colors.black,
pressedColor: Colors.grey,
children: {
_Tab.one: Text('One'),
_Tab.two: Text('Two'),
},
onValueChanged: (value) {
setState(() {
_selectedTab = value;
});
},
groupValue: _selectedTab,
),
SizedBox(height: 64),
Builder(
builder: (context) {
switch (_selectedTab) {
case _Tab.one:
return Center(
child: Container(
width: 100,
height: 100,
color: Colors.red,
),
);
case _Tab.two:
return Center(
child: Container(
width: 100,
height: 100,
color: Colors.blue,
),
);
}
},
),
],
);
}
}
Also take a look at CupertinoSlidingSegmentedControl.
for your requirement don't use TabBarView at all, directly use container, change it's color value as per selectedtab index
class Tabscreenstate extends State<Tabscreen> with TickerProviderStateMixin {
int selectedTabIndex = 0;
TabController tabController;
#override
void initState() {
tabController = TabController(length: 2, vsync: this);
tabController.addListener(() {
setState(() {
selectedTabIndex = tabController.index;
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Column(
children: [
tabbar(),
Container(color:selectedTabIndex == 0 ? Colors.red : Colors.green),
],
);
}
Widget tabbar() => TabBar(
controller: tabController,
onTap: (value) {
setState(() {
selectedTabIndex = value;
});
},
tabs: [
Text("tab one"),
Text("tab two"),
],
);
}
How to create basic design like from sketch from image. First container with list of tabs is static, and containers above it is dynamic, and contain text - Text for tab 1 if tab 1 is clicked, or Text for tab 2 if tab 2 is clicked. Also text for Tab1 or Tab2 must be underline if we click on it.
Something like this:
Using a GestureDetector widget to tell when a user taps on the tabs and then updating the state with setState is maybe the most simple way of doing this.
Here is a very basic example of using a stateful widget and setState to update the page. You can approach this problem with any state management strategy, though.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: Scaffold(body: MyHomePage()),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String selectedTab;
static const String TAB_1 = 'Tab 1';
static const String TAB_2 = 'Tab 2';
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
flex: 1,
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
GestureDetector(
onTap: () {
setState(() => selectedTab = TAB_1);
},
child: Container(
padding: const EdgeInsets.all(12.0),
child: Text(TAB_1),
decoration: selectedTab == TAB_1
? BoxDecoration(border: Border(bottom: BorderSide()))
: null,
),
),
GestureDetector(
onTap: () {
setState(() => selectedTab = TAB_2);
},
child: Container(
padding: const EdgeInsets.all(12.0),
child: Text(TAB_2),
decoration: selectedTab == TAB_2
? BoxDecoration(border: Border(bottom: BorderSide()))
: null,
),
)
],
),
),
Container(height: 20.0),
Expanded(
flex: 2,
child: Container(
decoration: BoxDecoration(
border: Border.all(width: 5),
borderRadius: BorderRadius.circular(12.0)),
child: Center(child: Text(textForTab(selectedTab))),
),
)
],
);
}
String textForTab(String tabId) {
switch (tabId) {
case TAB_1:
return 'Text for Tab 1';
case TAB_2:
return 'Text for Tab 2';
default:
return 'Select Tab';
}
}
}
You can do it using TabBar widget.
class CustomTabBar extends StatefulWidget {
#override
_CustomTabBarState createState() => _CustomTabBarState();
}
class _CustomTabBarState extends State<CustomTabBar>
with SingleTickerProviderStateMixin {
TabController _tabController;
#override
void initState() {
_tabController = TabController(length: 2, vsync: this);
super.initState();
}
#override
void dispose() {
super.dispose();
_tabController.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'Tab Demo',
),
),
body:
Column(
children: [
Container(
height: 45,
child: TabBar(
controller: _tabController,
indicator: BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.blue,width: 2,style:
BorderStyle.solid)),
),
labelColor: Colors.blue,
unselectedLabelColor: Colors.black,
tabs: [
// first tab
Tab(
text: 'Home',
),
// second tab
Tab(
text: 'Profile',
),
],
),
),
// tab bar view
Expanded(
child: TabBarView(
controller: _tabController,
children: [
// first tab widget
Center(
child: Text(
'Home',
style: TextStyle(
fontSize: 26,
fontWeight: FontWeight.bold,
),
),
),
// Second tab widget
Center(
child: Text(
'Profile',
style: TextStyle(
fontSize: 26,
fontWeight: FontWeight.bold,
),
),
),
],
),
),
],
),
);
}
}
I'm not sure I understand you completely.
But if you want to implement a TabBar, you can use flutter TabBar() documented here:
https://flutter.dev/docs/cookbook/design/tabs
Or there is a package you can use:
https://pub.dev/packages/tabbar
i have tried to recreate this design but failed to add TabBar and TabBarView below image inside the body .
Try this
class Demo extends StatefulWidget {
#override
_DemoState createState() => _DemoState();
}
class _DemoState extends State<Demo>
with TickerProviderStateMixin {
TabController _tabController;
#override
void initState() {
// TODO: implement initState
super.initState();
_tabController = new TabController(length: 2, vsync: this);
}
#override
void dispose() {
_tabController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body:Column(
children: <Widget>[
Image.asset("path"),
Container(child:
Column(
children: <Widget>[
Container(
height: 60,
margin: EdgeInsets.only(left: 60),
child: TabBar(
tabs: [
Container(
width: 70.0,
child: new Text(
'Tab1',
style: TextStyle(fontSize: 20),
),
),
Container(
width: 75.0,
child: new Text(
'Tab2',
style: TextStyle(fontSize: 20),
),
)
],
unselectedLabelColor: const Color(0xffacb3bf),
indicatorColor: Color(0xFFffac81),
labelColor: Colors.black,
indicatorSize: TabBarIndicatorSize.tab,
indicatorWeight: 3.0,
indicatorPadding: EdgeInsets.all(10),
isScrollable: false,
controller: _tabController,
),
),
Container(
height: 100,
child: TabBarView(
controller: _tabController,
children: <Widget>[
Container(
child: Text("login"),
),
Container(
child: Text("sign up"),
)
]),
))
],
),
],
)
);
}
You can easily create TabBar without AppBar. Just use Container as parent.
please check this.
Expanded(
child: DefaultTabController(
length: 3,
child: new Scaffold(
appBar: new PreferredSize(
preferredSize:
Size.fromHeight(MediaQuery.of(context).size.height),
child: new Container(
height: 50.0,
child: new TabBar(
labelColor: Colors.black,
isScrollable: true,
tabs: [
Tab(
text: "Tab 1",
),
Tab(
text: "Tab 2",
),
Tab(
text: "Tab 3",
),
],
),
),
),
body: TabBarView(
children: [
Icon(Icons.directions_car),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
],
),
),
),
)
I've put on a simple example, have a look and see if it can help you:
First define a Statefull widget and add some definition regarding your tab
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
Define the state for your widget
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
TabController _tabController;
final List<Tab> tabs = [
Tab(
///Give keys so you can make it easier to retrieve content to display, if you have to read the data from a remote resource ...
key: ObjectKey(1),
text: 'Products',
),
Tab(
key: ObjectKey(2),
text: 'Feature',
),
Tab(
key: ObjectKey(3),
text: 'Shipping Info',
),
Tab(
key: ObjectKey(4),
text: 'Reviews',
),
];
///Build the widget for each tab ...
Widget _setDisplayContainer(key) {
if (key == ObjectKey(1)) {
return Text("Content for tab 1");
} else if (key == ObjectKey(2)) {
return Text("Content for tab 2");
} else if (key == ObjectKey(3)) {
return Text("Content for tab 3");
}
return Text("Content for tab 4");
}
#override
void initState() {
super.initState();
_tabController = TabController(vsync: this, length: tabs.length);
}
...
}
After this your build method should look something like this
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize: Size(MediaQuery.of(context).size.width,
MediaQuery.of(context).size.height * .4),
child: SafeArea(
child: Column(
children: <Widget>[
Container(
child: Expanded(
flex: 4,
child: Stack(fit: StackFit.loose, children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('images/car.jpeg'),
fit: BoxFit.cover,
)),
),
Container(
height: 40,
color: Colors.orangeAccent,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Icon(Icons.arrow_back,
color: Colors.white, size: 20),
Row(
children: <Widget>[
Icon(
Icons.search,
color: Colors.white,
size: 20,
),
Icon(Icons.menu, color: Colors.white, size: 20),
],
)
],
),
),
]),
),
),
Container(
child: TabBar(
unselectedLabelColor: const Color(0xffacb3bf),
indicatorColor: Color(0xFFffac81),
labelColor: Colors.black,
indicatorSize: TabBarIndicatorSize.tab,
indicatorWeight: 3.0,
indicatorPadding: EdgeInsets.all(10),
tabs: tabs,
controller: _tabController,
labelStyle: TextStyle(color: Colors.orangeAccent, fontSize: 12),
onTap: (index) {},
),
),
],
),
),
),
body: TabBarView(
controller: _tabController,
children:
tabs.map((tab) => _setDisplayContainer(tab.key)).toList()));
}
Hope this helps.
I have two tab. I want elevation bottom of Appbar and elevation bottom of TabBarView. How can I do this?
Here is my Code,
class MyOrder extends StatefulWidget {
#override
_MyOrderState createState() => _MyOrderState();
}
class _MyOrderState extends State<MyOrder> with SingleTickerProviderStateMixin{
var strTitle = Translations.globalTranslations.myOrders;
TabController _tabController;
#override
void initState() {
_tabController = new TabController(length: 2, vsync: this);
super.initState();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
elevation: 1.0,
leading: new IconButton(
icon: Image.asset('images/keyboard_backspace.png', width: 24.0, height: 24.0,),
onPressed: () => Navigator.of(context).pop(),
),
title: Text(strTitle,textAlign: TextAlign.left , style: UIUtills().getTextStyle(
fontName: AppFontName.appFontSemiBold,
fontsize: 20,
color: AppColor.redColor),),
backgroundColor: Colors.white,
iconTheme: IconThemeData(
color: AppColor.redColor),
bottom: TabBar(
indicatorColor: AppColor.redColor,
labelColor: AppColor.blackColor,
labelStyle: UIUtills().getTextStyle(
fontName: AppFontName.appFontSemiBold,
fontsize: 16,
color: AppColor.blackColor),
tabs: [
new Tab(text:Translations.globalTranslations.pastOrder),
new Tab(text: Translations.globalTranslations.upComing)
],
controller: _tabController,
indicatorSize: TabBarIndicatorSize.tab),
),
body: TabBarView(
children: [
PastOrder(),
UpComingOrder(),
],
controller: _tabController,),
);
}
}
As per my code layout looks like,
https://i.stack.imgur.com/D9BND.png
I want to design my layout like this,
https://i.stack.imgur.com/tPv8A.png
Try this one
ScreenShot https://imgur.com/Fz95DEr
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 8.0, // top bar
leading: InkWell(
onTap: () {},
child: Icon(
Icons.keyboard_arrow_left,
color: Colors.red,
),
),
backgroundColor: Colors.white,
title: Text(
"My Order",
style: TextStyle(color: Colors.red),
),
),
body: Scaffold(
body: DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
elevation: 8.0, // bottom bar
bottom: PreferredSize(
child: TabBar(
labelColor: Colors.black,
indicatorColor: Colors.red,
tabs: <Widget>[
Tab(
text: "Past Order",
),
Tab(
text: "Upcoming",
),
],
),
preferredSize: Size.fromHeight(0.0),
),
backgroundColor: Colors.white,
),
body: TabBarView(
children: <Widget>[
Container(
color: Colors.white,
child: Center(
child: Text("Past Order"),
),
),
Container(
color: Colors.white,
child: Center(
child: Text("Upcoming"),
),
),
],
),
),
),
),
);
}
}