What I want to do is to when pressed a movie tab it shows NowPlayedMovies() and BestMovies(), and when pressed tv shows tab to show NowPlayedTV() and BestTV(). At first I was using ListView but because I'm using tabs i need to use TabBarView. So in my child method I created 2 methods buildPage1 and buildPage2 in which I have put my 2 methods as mentioned above.
When I tried to run the code it displayed this error:
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following NoSuchMethodError was thrown building _TabControllerScope:
The getter 'key' was called on null.
Receiver: null
Tried calling: key
The relevant error-causing widget was:
DefaultTabController
Here is my code:
class HomePageMovie extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePageMovie> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFF151C26),
appBar: AppBar(
backgroundColor: Color(0xFF151C26),
title: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SvgPicture.asset(
logo,
height: 195,
),
],
),
actions: <Widget>[
IconButton(
onPressed: () {},
icon: Icon(
EvaIcons.searchOutline,
color: Colors.white,
))
],
titleSpacing: 0.0,
bottom: PreferredSize(
preferredSize: Size.fromHeight(75.0),
child: DefaultTabController(
length: 2,
child: TabBar(
indicatorColor: Color(0xFFf4C10F),
indicatorWeight: 4.0,
unselectedLabelColor: Colors.white,
labelColor: Colors.white,
tabs: [
Tab(
icon: Icon(Icons.movie),
child: Text(
"Movies",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 14.0),
),
),
Tab(
icon: Icon(Icons.live_tv),
child: Text(
"TV Shows",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 14.0),
),
)
]),
),
),
),
body: DefaultTabController(
length: 2,
child: TabBarView(
children: [buildPage1(), buildPage2()],
),
));
}
buildPage1() {
NowPlayingMovies();
BestMovie();
}
buildPage2() {
NowPlayingTV();
BestTV();
}
}
Here is visual representation of what I'm trying to achieve:
Any help would be great. Thanks in advance :)
Use only one DefaultTabBarController at the top of your widget tree (in this case, as a parent of your Scaffold and remove the other two).
You should only use a single DefaultTabBarController that is shared between the TabBar and the TabBarView.
So with help of Miguel what I did wrong was I didn't put a specific controller to connect these 2, in my case as a solution I wrapped them both in common default controller. As of the 2nd part of the problem what I did is simply put ListView to display these 2
The code of solution:
class _HomePageState extends State<HomePageMovie> {
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
backgroundColor: Color(0xFF151C26),
appBar: AppBar(
backgroundColor: Color(0xFF151C26),
title: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SvgPicture.asset(
logo,
height: 195,
),
],
),
actions: <Widget>[
IconButton(
onPressed: () {},
icon: Icon(
EvaIcons.searchOutline,
color: Colors.white,
))
],
titleSpacing: 0.0,
bottom: PreferredSize(
preferredSize: Size.fromHeight(75.0),
child: TabBar(
indicatorColor: Color(0xFFf4C10F),
indicatorWeight: 4.0,
unselectedLabelColor: Colors.white,
labelColor: Colors.white,
tabs: [
Tab(
icon: Icon(Icons.movie),
child: Text(
"Movies",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 14.0),
),
),
Tab(
icon: Icon(Icons.live_tv),
child: Text(
"TV Shows",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 14.0),
),
)
]),
),
),
body: TabBarView(
children: [
ListView(
children: <Widget>[NowPlayingMovies(), BestMovie()],
),
ListView(
children: <Widget>[
NowPlayingTV(),
BestTV(),
],
),
],
),
),
);
}
}
Related
How I can control the tabs , so it can shows up like this design
I try but I can't control the space before and after tabs in TabBar.
I do not understand what you mean by controlling tabs but check the below code for tab bar implementation, along with drawers and appbar action icons.
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 3, //this is the number of tabs you need -- for your case it is 3
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.brown[500],
actions: [
IconButton(onPressed: () {
//This is to show a snackbar message when search button is pressed. Remove it and put your own onpressed action code
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Text("Search Button Pressed"),
behavior: SnackBarBehavior.floating,
margin: const EdgeInsets.all(20),
shape: const StadiumBorder(),
action: SnackBarAction(
label: 'Dismiss',
disabledTextColor: Colors.white,
textColor: Colors.blue,
onPressed: () {
//Do whatever you want
},
),
),
);
}, icon: const Icon(Icons.search)),
],
bottom: const TabBar(
//customise your tabs here
indicatorColor: Colors.white,
indicatorSize: TabBarIndicatorSize.label,
indicatorWeight: 5,
labelStyle: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold),
tabs: [
//add your tabs here. if you add more tabs make sure you increase the length above
Tab(text: 'Doctor', iconMargin: EdgeInsets.zero,),
Tab(text: 'Community',),
Tab(text: 'Calls',),
],
),
),
//This is your app drawer
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
const DrawerHeader(
decoration: BoxDecoration(
color: Colors.blue,
),
child: Text('Drawer Header'),
),
ListTile(
title: const Text('Item 1'),
onTap: () {},
),
ListTile(
title: const Text('Item 2'),
onTap: () {},
),
],
),
),
body: const TabBarView(
//This is the view of all the tabs. The first children in the list is the first item in tabs.
children: [
Center(child: Text('Doctor Page', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30),)),
Center(child: Text('Community Page', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30),)),
Center(child: Text('Calls Page', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30),)),
],
),
),
);
}
}
Output:
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
leading: const Icon(Icons.home),
automaticallyImplyLeading: true,
title: const Text('test app'),
foregroundColor: Colors.black,
actions: [
IconButton(
onPressed: () {},
icon: const Icon(Icons.menu),
),
],
),
body: Container(
child: Column(
children: [
Row(
children: [
const Text(
'New',
style: TextStyle(
color: Colors.black54,
fontSize: 40,
fontWeight: FontWeight.bold,
fontStyle: FontStyle.italic,
height: 2,
shadows: [
Shadow(color: Colors.black12, offset: Offset(4, 10))
]),
),
ElevatedButton.icon(onPressed: (){}, icon: Icon(Icons.navigate_next),label: Text(' '),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.grey),
),
),
],
),
Row(),
],
),
),
),
);
}
use the Row widget properties for laying out its childrens
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [....]
)
the official docs are helpful in that matter
https://api.flutter.dev/flutter/widgets/Row-class.html
sidenote: if you are not planning to use any of the first container() properties then its better to get rid of it
There are 4 options u can use depending on what you want
If u want it below new u can use Column instead of Row .
If u want to put some space next to new u can use SizedBox(width:X) between the Text and the elevated button.
You can use mainAxisAlignment or crossAxisAlignment inside the row or column to customize the position
you can find examples about them here https://docs.flutter.dev/development/ui/layout
you can use margin or padding on elevated button to customize its own position
I have a class where there are 2 Tabs (used DefaultTabController) . AppBar have Action button/Text to save the Edited Text in each tab either It may tab0 or tab1. Both Tabs are separate stateful widget . I don't know, how to get How to get EditedText/String from a tab when save action is pressed in main Class ?
I looked into the similar Question but didn't get idea from it Flutter: send Data from TabBarView (StatefullWidgets) back to main Scaffold
your help would be appreciated .Thanks a lot.
class EditPocketMoney extends StatefulWidget {
#override
_EditPocketMoneyState createState() => _EditPocketMoneyState();
}
class _EditPocketMoneyState extends State<EditPocketMoney> {
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
backgroundColor: Theme.of(context).primaryColor,
appBar: AppBar(
elevation: 0.0,
automaticallyImplyLeading: false,
leading: IconButton(icon: Icon(Icons.clear,color: Color(0xffE44663),), onPressed: (){Navigator.pop(context);}),
title: Text('Edit',style: TextStyle(color: Colors.white,fontFamily: 'SF Pro Text',fontSize: 17.0, ),),
centerTitle: true,
actions: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
InkWell(
onTap: (){
},
child: Container(
margin:EdgeInsets.only(right:15.0 ),
child: Text('SAVE',style: TextStyle(color: Color(0xffE44663),fontFamily: 'SF Pro Text',fontSize: 17.0, ),)),
),
],
),
],
bottom: PreferredSize(
preferredSize: Size(MediaQuery.of(context).size.width*0.8, 45.0),
child: Container(
margin: EdgeInsets.only(left: 18.0,right: 18.0,top: 5.0),
child: TabBar(
unselectedLabelColor: Colors.white,
labelColor:Colors.black ,
labelPadding: EdgeInsets.all(8.0),
tabs: [
Center(child: Text('Per Day',style: TextStyle(fontSize: 15.0,fontWeight: FontWeight.w600),)),
Center(child: Text('Per Month',style: TextStyle(fontSize: 15.0,fontWeight: FontWeight.w600),)),
],
indicator: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
color: Colors.white,
),),
),
),
),
body: TabBarView(children: [
PocketMoneyPerDay(),
PocketMoneyEditPerMonth()
])
),
);
}
You can use any State Management package like Provider.
Refer this link for Provider https://medium.com/flutterpub/provider-state-management-in-flutter-d453e73537c5
I have given example using Provider package.
ChangeNotifier code:
class Data extends ChangeNotifier {
TextEditingController tab_0_controller = TextEditingController();
TextEditingController tab_1_controller = TextEditingController();
}
Tab0 TextField code:
TextField(
controller: Provider.of<Data>(context).tab_0_controller;
)
I'm trying to create a tab bar at the center of the screen using flutter while trying it I gave TabBarView in a column and I was stuck in this error. Please resolve this.
I/flutter ( 3983): ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter ( 3983): The following assertion was thrown during performResize():
I/flutter ( 3983): Horizontal viewport was given unbounded height.
I/flutter ( 3983): Viewports expand in the cross axis to fill their container and constrain their children to match
I/flutter ( 3983): their extent in the cross axis. In this case, a horizontal viewport was given an unlimited amount of
I/flutter ( 3983): vertical space in which to expand.
The source code is
class profilePage extends StatefulWidget {
#override
profilePageState createState() => profilePageState();
}
class profilePageState extends State<profilePage>
with SingleTickerProviderStateMixin {
TabController _tabController;
#override
void initState() {
_tabController = new TabController(length: 2, vsync: this);
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: [
Container(
child: Column(crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
height: 40,
),DefaultTabController(
length: 2,
child: Column(children: [TabBar(
unselectedLabelColor: Colors.black,
labelColor: Colors.red,
tabs: <Widget>[
Tab(
icon: Icon(Icons.people),
),
Tab(
icon: Icon(Icons.person),
)
],controller: _tabController,
indicatorSize: TabBarIndicatorSize.tab,
),TabBarView(
children: <Widget>[Text('people'), Text('Person')],
controller: _tabController,
),
]),
),
],
),
),
],
),
);
}
}
You can see the above model of the image what I'm trying to achieve. I've tried many things but I've stuck here.
How to rectify this error and how to create a tab bar at the center of my screen?
I added a demo of what you are trying to get (I followed the Image you posted):
NOTE : I had to make few changes to the way you arranged your widget tree.
class profilePage extends StatefulWidget {
#override
profilePageState createState() => profilePageState();
}
class profilePageState extends State<profilePage> {
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
title: Text(
'My Profile',
),
centerTitle: true,
backgroundColor: Colors.grey[700].withOpacity(0.4),
elevation: 0,
// give the app bar rounded corners
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(20.0),
bottomRight: Radius.circular(20.0),
),
),
leading: Icon(
Icons.menu,
),
),
body: Column(
children: <Widget>[
// construct the profile details widget here
SizedBox(
height: 180,
child: Center(
child: Text(
'Profile Details Goes here',
),
),
),
// the tab bar with two items
SizedBox(
height: 50,
child: AppBar(
bottom: TabBar(
tabs: [
Tab(
icon: Icon(Icons.directions_bike),
),
Tab(
icon: Icon(
Icons.directions_car,
),
),
],
),
),
),
// create widgets for each tab bar here
Expanded(
child: TabBarView(
children: [
// first tab bar view widget
Container(
color: Colors.red,
child: Center(
child: Text(
'Bike',
),
),
),
// second tab bar viiew widget
Container(
color: Colors.pink,
child: Center(
child: Text(
'Car',
),
),
),
],
),
),
],
),
),
);
}
}
OUTPUT:
To put the TabBar at the center of the screen, your Profile Container's height should be the screen height divided by 2
Like this
class profilePage extends StatefulWidget {
#override
profilePageState createState() => profilePageState();
}
class profilePageState extends State<profilePage>
with SingleTickerProviderStateMixin {
TabController _tabController;
#override
void initState() {
_tabController = new TabController(length: 2, vsync: this);
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
height: MediaQuery.of(context).size.height /2,
child: Center(child: Text("Profile"),),
color: Colors.blue,
),
TabBar(
unselectedLabelColor: Colors.black,
labelColor: Colors.red,
tabs: [
Tab(
icon: Icon(Icons.people),
),
Tab(
icon: Icon(Icons.person),
)
],
controller: _tabController,
indicatorSize: TabBarIndicatorSize.tab,
),
Expanded(
child: TabBarView(
children: [Text('people'), Text('Person')],
controller: _tabController,
),
),
],
),
),
);
}
}
Result:
Also can try this,
AppBar(
leading: IconButton(
constraints: BoxConstraints(),
padding: EdgeInsets.zero,
icon: Container(
padding: EdgeInsets.fromLTRB(10, 5, 0, 5),
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(20)),
// color: MyColors.primaryColorLight.withAlpha(20),
color: Colors.white,
),
child: Icon(
Icons.arrow_back_ios,
color: kPrimaryColor,
// size: 16,
),
),
onPressed: () => Navigator.of(context).pop(),
),
backgroundColor: kPrimaryColor,
toolbarHeight: 80,
elevation: 5.0,
title: TabBar(//Add tab bar to title
indicator: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(30)),
color: Colors.white),
labelColor: kPrimaryColor,
unselectedLabelColor: Colors.white,
indicatorSize: TabBarIndicatorSize.label,
isScrollable: true,
tabs: [
Container(
height: 30.0,
width: 100,
child: Tab(
child: Align(
alignment: Alignment.center,
child: Text(
"Ongoing",
style: TextStyle(fontSize: 16),
),
),
),
),
Container(
width: 100,
height: 30.0,
child: Tab(
child: Align(
alignment: Alignment.center,
child: Text(
"Requests",
style: TextStyle(fontSize: 16),
),
),
),
),
],
),
)
I'm trying to change color of the tab icon when tab is selected. I know how to change the color of the icon, but I don't know how to make the color change when I select tab.
My code:
child: AppBar(
bottom: TabBar(
tabs: <Tab>[
Tab(
child: new Row(
children: <Widget>[
new Text("Select", textAlign: TextAlign.start),
new SizedBox(
width: 24.0,
),
new Icon(
Icons.arrow_drop_down,
color: Colors.blue.shade400,
),
],
....
)
)
]
)
)
To change the selected tab color, you just need to add this to TabBar :
labelColor: Colors.
unselectedLabelColor: Colors.white,
Full code:
DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
labelColor: Colors.deepOrange,
unselectedLabelColor: Colors.white,
tabs: <Tab>[
Tab(
child: Row(
children: <Widget>[
Text("Select", textAlign: TextAlign.start),
SizedBox(
width: 24.0,
),
Icon(
Icons.arrow_drop_down,
color: Colors.blue.shade400,
),
],
),
),
Tab(
child: Row(
children: <Widget>[
Text("Select", textAlign: TextAlign.start),
SizedBox(
width: 24.0,
),
Icon(
Icons.arrow_drop_down,
color: Colors.blue.shade400,
),
],
),
),
],
),
),
body: Center(
child: Container(
child: Text("This is a page blahblah"),
),
),
),
)
EDIT:
If u want to only change the icon color, then add color to Text and remove the color from the Icon in Tab, Code:
DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
labelColor: Colors.deepOrange,
unselectedLabelColor: Colors.white,
tabs: <Tab>[
Tab(
child: Row(
children: <Widget>[
Text("Select", textAlign: TextAlign.start, style: TextStyle(color: Colors.white),),
SizedBox(
width: 24.0,
),
Icon(
Icons.arrow_drop_down,
),
],
),
),
Tab(
child: Row(
children: <Widget>[
Text("Select", textAlign: TextAlign.start, style: TextStyle(color: Colors.white),),
SizedBox(
width: 24.0,
),
Icon(
Icons.arrow_drop_down,
),
],
),
),
],
),
),
body: Center(
child: Container(
child: Text("This is a page blahblah"),
),
),
),
)
EDIT #2
Now , This code changes the Icon color, but leaves the text color change as default (You can customize the change for color of text like the icon color). Code:
import 'package:flutter/material.dart';
class FirstPage extends StatefulWidget {
#override
_FirstPageState createState() => _FirstPageState();
}
class _FirstPageState extends State<FirstPage> {
int _currentIndex = 0;
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
onTap: (index){
setState(() {
_currentIndex = index;
});
},
tabs: <Tab>[
Tab(
child: Row(
children: <Widget>[
Text("Select", textAlign: TextAlign.start,),
SizedBox(
width: 24.0,
),
Icon(
Icons.arrow_drop_down,
color: _currentIndex == 0 ? Colors.deepOrange : Colors.white54
),
],
),
),
Tab(
child: Row(
children: <Widget>[
Text("Select", textAlign: TextAlign.start,),
SizedBox(
width: 24.0,
),
Icon(
Icons.arrow_drop_down,
color: _currentIndex == 1 ? Colors.deepOrange : Colors.white54,
),
],
),
),
],
),
),
body: Center(
child: Container(
child: Text("This is a page blahblah"),
),
),
),
);
}
}
TabBar has the properties labelColor and unselectedLabelColor to set a selected/unselected color to any icon and text in the Tabs.
If you want to have a fixed color for icons or texts in the Tabs, you just have to specify that color in the Icon or Text in the Tab to override the color defined in the properties labelColor and unselectedLabelColor of the TabBar.
So, in your case, if you want to have a selected/unselected color for icons and a fixed color for the text, you have to set the labelColor and unselectedLabelColor in the TabBar with the colors for the icons and set a specific color on the text inside the Tabs.
Create a custom tab controller as shown click here
Do something like _tabController.index to get the index of the current tab.
For each tab check if its position(starting from 0) matches the TabController index and display the appropriate icon