I'm trying to use the curvedNavigationBar package. Here is my code :
Widget build(BuildContext context) {
int currentTab = 2;
return Scaffold(
key: _scaffoldKey,
bottomNavigationBar: CurvedNavigationBar(
key: _bottomNavigationKey,
index: currentTab,
height: 50.0,
items: <Widget>[
Icon(Icons.home, color:currentTab==0?Colors.yellow:Colors.black, size: 30),
Icon(Icons.wifi_tethering, color:currentTab==1?Colors.yellow:Colors.black, size: 30),
Icon(Icons.flag, color:currentTab==2?Colors.yellow:Colors.black, size: 65),
Icon(Icons.mail, color:currentTab==3?Colors.yellow:Colors.black, size: 30),
Icon(Icons.account_circle, color: currentTab==4?Colors.yellow:Colors.black, size: 30),
],
color: Colors.yellow,
buttonBackgroundColor: Colors.black,
backgroundColor: Colors.black,
animationCurve: Curves.bounceInOut,
animationDuration: Duration(milliseconds: 200),
onTap: (index) {
setState(() {
currentTab = index;
});
},
),
body: Container(
color: Colors.black,
child: Center(
child: Column(
children: <Widget>[
Text(_page.toString(), textScaleFactor: 10.0),
RaisedButton(
child: Text('Go To Page of index 1'),
onPressed: () {
final CurvedNavigationBarState navBarState =
_bottomNavigationKey.currentState;
navBarState.setPage(1);
},
),
],
),
),
),
appBar: AppBar(
backgroundColor: Colors.yellow,
leading: Padding(
child: GestureDetector(
onTap: () {
_scaffoldKey.currentState.openDrawer();
},
child: CircleAvatar(
backgroundImage: ExactAssetImage('images/profile.jpg'),
radius: 30,
),
),
padding: const EdgeInsets.all(8.0),
),
title: Text("Title"),
),
drawer: DrawerCustom("Vogan", "#jbbo"),
drawerEdgeDragWidth: 0,
);
on the setState methode, I'm giving currentTab the index's value. But the icons are not being refresh, the color stay the same. I have watched for fixedColor but the package doesnt not handle this kind of properties. Same for activeIcons inside a navigationbarItem, because items property of curvednavigationBar is a list of widget. So I can not use a navigationbarItem.
How can I fix this problem?
edit
Thought it was maybe because I didn't initialize state so I did add this:
#override
void initState(){
super.initState();
}
It is still not working, I don't get it. The onPressed is working well, when I click on an icon, I go inside the method, currentTab value is updated but the icon's colors stay unchanged.
Founded it ! It was because my variable currentTab was not a global variable of the class, i declare it inside the build method, that was a mistake
Related
I have a DefaultTabController with two pages nested in a scaffold. In my scaffold's App Bar is a save button and I want this button to return a value to a previous page, based on a variable that is calculated in one of the tabs. How do I get this value?
Here is my DefaultTabController
DefaultTabController(
initialIndex: index,
length: 2,
child: Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: AppBar(
elevation: 0,
backgroundColor: fumigruen_accent,
leading: CloseButton(
color: Colors.black,
onPressed: () {
Navigator.of(context).pop();
},
),
actions: buildEditingActions(),
),
body: Column(children: [
tabBar(),
Expanded(
child: TabBarView(children: [
//1st Tab
GewichtsrechnerEinfach(),
//2nd Tab
Column()
]),
)
]),
));}
And here is the save-Button I want to use to pass a varaible to the previous screen
List<Widget> buildEditingActions() => [
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: fumigruen_accent,
elevation: 0,
foregroundColor: Colors.black,
),
onPressed: () {
Navigator.of(context).pop(gewicht);
},
icon: Icon(Icons.save),
label: Text("Speichern"))
];
The tabbar Code
Widget tabBar() => TabBar(
labelColor: Theme.of(context).primaryColor,
indicatorColor: Theme.of(context).primaryColor,
labelStyle: TextStyle(fontWeight: FontWeight.bold),
tabs: [
Tab(
child: Row(mainAxisSize: MainAxisSize.min, children: [
Icon(
Icons.assessment_outlined,
),
SizedBox(
width: 5,
),
Text("Einfach")
]),
),
Tab(
child: Row(mainAxisSize: MainAxisSize.min, children: [
Icon(
Icons.addchart,
),
SizedBox(
width: 5,
),
Text("Fortgeschritten")
]),
),
]);
and an extract of the GewichtsrechnerEinfach():
class _GewichtsrechnerEinfachState extends State<GewichtsrechnerEinfach> {
final _formKey = GlobalKey<FormState>();
num koerperlaenge = 0;
num brustumfang = 0;
var _koerperlaengeControler = TextEditingController();
var _brustumfangControler = TextEditingController();
num gewicht = 0;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//{two textinput fields setting the variables koerperlaenge and brustumfang are here}
Center(
child: Container(
width: MediaQuery.of(context).size.width * 0.8,
decoration: ThemeHelper().buttonBoxDecoration(context),
child: ElevatedButton(
style: ThemeHelper().buttonStyle(),
child: Padding(
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
child: Text(
"berechnen".toUpperCase(),
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
onPressed: () async {
if (_formKey.currentState!.validate()) {
setState(() {
gewicht = Gewichtskalkulator().einfach(
brustumfang.toDouble(),
koerperlaenge.toDouble());
});
}
}),
),
),
],
),
),
),
);
}
The variable "gewicht" is calculated and changed in the first tab "GewichtsrechnerEinfach". So how do I get the changed variable to this main screen so that I can use it while saving?
Thanks a lot :)
As I found out by chatting in comments section, you are changing a value in a Page and you want to use it in another pages or screen, this is why you should use StateManagement something like Provider.
As you said you need to change the gewicht variable and use it where ever you want.
step 1) please add provider: ^6.0.5 (or any version that is compatible) in your pubspec.yaml and call flutter pub get.
step 2) now you should create a provider class to make all the variables that you want to use everywhere, alive. please create a dart file named:
gewichtsrechner_einfach_provider.dart
step 3) now you should put these codes in you provider class:
import 'package:flutter/material.dart';
class GewichtsrechnerEinfachProvider extends ChangeNotifier{
num _gewicht = 0;
num get gewicht => _gewicht;
void setGewicht(num newGewicht){
_gewicht = newGewicht;
notifyListeners();
}
}
as you see _gewicht is private and you can use it alive entire your project.
step 4) you should add the provider to main.dart:
MultiProvider(
providers: [
// you are adding your provider
ListenableProvider.value(value: GewichtsrechnerEinfachProvider()),
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: ...........
),
);
step 5) now you should use its setter and getter of gewicht:
as you see in _GewichtsrechnerEinfachState you are setting the value and should do this by using Consumer:
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: SingleChildScrollView(
child: Consumer<GewichtsrechnerEinfachProvider>(//note this
builder: (context, gewichtsrechnerEinfachProvider ,child) {
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//{two textinput fields setting the variables koerperlaenge and brustumfang are here}
Center(
child: Container(
width: MediaQuery.of(context).size.width * 0.8,
decoration: ThemeHelper().buttonBoxDecoration(context),
child: ElevatedButton(
style: ThemeHelper().buttonStyle(),
child: Padding(
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
child: Text(
"berechnen".toUpperCase(),
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
onPressed: () async {
if (_formKey.currentState!.validate()) {
// and note this
gewichtsrechnerEinfachProvider.setGewicht(
Gewichtskalkulator().einfach(
brustumfang.toDouble(),
koerperlaenge.toDouble())
);
}
}),
),
),
],
),
);
}
),
),
);
}
step 6) now you should use its getter where ever you want:
List<Widget> buildEditingActions() => [
Consumer<GewichtsrechnerEinfachProvider>(
builder: (context, gewichtsrechnerEinfachProvider ,child) {
return ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: fumigruen_accent,
elevation: 0,
foregroundColor: Colors.black,
),
onPressed: () {
// Navigator.of(context).pop(gewicht);
print('here is your result:
${gewichtsrechnerEinfachProvider.gewicht}');
},
icon: Icon(Icons.save),
label: Text("Speichern"));
}
)
];
note that you can use your provider where ever you want even with this code not just consumer:
var gewichtsrechnerEinfachProvider = Provider.of<GewichtsrechnerEinfachProvider>(context,listen: false);
as you see by changing its value the provider notifies to where you are showing it.
Ich hoffe, ich konnte dir helfen ;)
happy coding my friend...
I am facing a problem with my custom app bar. I would like it to have a drawer but it doesn't work. I just don't know how to make it being able to open.
It is a custom app bar widget named Pasek (which stands for top bar in my language).
It has a logo picture which on click moves you to the first page of the app.
Next to it there is humburger menu with a drawer but I do not know why it doesn't work. I click on it and nothing happens.
Any ideas?
class Pasek extends StatelessWidget with PreferredSizeWidget {
#override
Size get preferredSize => Size.fromHeight(50.0);
const Pasek({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return AppBar(
actions: <Widget>[
Padding(
padding: EdgeInsets.only(right: 35.0),
child: ElevatedButton(
child: Icon(Icons.menu, color: Colors.white),
onPressed: () {
Scaffold(
endDrawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: const <Widget>[
DrawerHeader(
decoration: BoxDecoration(
color: Colors.black,
),
child: Text(
'Menu',
style: TextStyle(
color: Colors.pink,
fontSize: 24,
),
),
),
ListTile(
leading: Icon(Icons.message),
title: Text('Messages'),
),
ListTile(
leading: Icon(Icons.account_circle),
title: Text('Profile'),
),
ListTile(
leading: Icon(Icons.settings),
title: Text('Settings'),
),
],
),
),
);
},
)),
],
backgroundColor: Colors.black,
title: GestureDetector(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => FirstPage(),
),
);
}, // Image tapped
child: Image.asset(
'images/logo.png',
fit: BoxFit.scaleDown,
height: 30,
width: 200,
),
));
}
}
I am trying to reposition my "compass" icon near the "search" icon from the App bar. Everytime i try to make a change in the container with higher value 55 for example "padding: const EdgeInsets.symmetric(horizontal: 50)," i get error stack over flow. Also when i try to change the logo(png) the allingment, nothing happens. Help please!
Image
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
flexibleSpace: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: <Color>[Colors.pink[400], Colors.blue[400]]
),
),
),
title: Row(
children: [
Container(
alignment: Alignment.center,
height: 40,
child: SizedBox(
child: Image.asset(
'assets/images/logox.png',
)
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 50),
child: SizedBox(
child: Icon(
Icons.explore_rounded,
))),
// Container(child: Icon(Icons.explore_rounded)),
],
),
actions: [
GestureDetector(
onTap: () {
// authMethods.signOut();
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => SearchScreen(),
));
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Icon(Icons.search)),
)
],
),
drawer: MainDrawer(),
//body: Body(),
bottomNavigationBar: GradientBottomNavigationBar(
fixedColor: Colors.white,
backgroundColorStart: Colors.pink[400],
backgroundColorEnd: Colors.blue[400],
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home), title: Text('Home')),
BottomNavigationBarItem(
icon: Icon(Icons.wallet_membership), title: Text('QUA')),
BottomNavigationBarItem(
icon: Icon(Icons.help), title: Text('Help')),
],
currentIndex: _selectedIndex,
onTap: _onItemTapped,
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.pink,
elevation: 50,
hoverColor: Colors.red,
autofocus: true,
onPressed: () {
print('hi');
},
child: Icon(
Icons.comment,
),
tooltip: 'Pick Image',
),
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat);
}
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
}
There is actions property in AppBar widget which is mainly used to put icons in AppBar. And in your case centerTitle is used to align your image to center
Output
Full code
class MyHomePage extends StatefulWidget {
final Function onItemPressed;
MyHomePage({
Key key,
this.onItemPressed,
}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
flexibleSpace: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: <Color>[Colors.pink[400], Colors.blue[400]]),
),
),
centerTitle: true,
title: Container(
alignment: Alignment.center,
height: 40,
child: SizedBox(
child: Image.asset(
'assets/logo.png',
)),
),
actions: [
IconButton(
onPressed: () {},
icon: Icon(Icons.explore_rounded),
),
IconButton(
onPressed: () {},
icon: Icon(Icons.search),
)
],
),
);
}
}
Material appbar has an actions property, you can use that to put search and compass icon together. In order to achieve the same remove
Container(
padding: const EdgeInsets.symmetric(horizontal: 50),
child: SizedBox(
child: Icon(
Icons.explore_rounded,
))),
from its current position and add it into the actions property just above the search button.
I have a problem with fetching value from database document to a variable called in initState method. When I am doing that there is a problem with null value and I think that get() method from Firebase is taking the value too late(it happens when i reload the scene).
bool _dark;
bool options;
MainModel model;
final MyUser myUser;
final UserSettings userSettings;
_SettingsOnePageState(this.userSettings, this.myUser);
final user = FirebaseAuth.instance.currentUser;
#override
void initState() {
super.initState();
// _dark = false;
FirebaseFirestore.instance
.collection("settings")
.doc(user.uid)
.get()
.then((value) {
print(value.data()['darkMode']);
_dark = value.data()['darkMode'];
});
options = false;
}
Brightness _getBrightness() {
return _dark ? Brightness.dark : Brightness.light;
}
#override
Widget build(BuildContext context) {
return Theme(
// return StreamProvider<QuerySnapshot>.value(
isMaterialAppTheme: true,
data: ThemeData(
brightness: _getBrightness(),
),
// value: SettingsUser().settings,
child: StreamBuilder<UserSettings>(
//setting the stream for settings from database
stream: DatabaseUser(userId: user.uid).userData,
builder: (context, snapshot) {
if (snapshot.hasData) {
//data for user from database
UserSettings userSettings = snapshot.data;
// _dark = userSettings.darkMode;
// print("dark mode " + userSettings.darkMode.toString());
return Form(
key: _formKey,
child: Scaffold(
backgroundColor: _dark ? null : Colors.grey.shade200,
appBar: AppBar(
//elevation: 10,
brightness: _getBrightness(),
iconTheme: IconThemeData(
color: _dark ? Colors.white : Colors.black),
backgroundColor: Colors.transparent,
title: Text(
'Change theme',
style: TextStyle(
color: _dark ? Colors.white : Colors.black),
textAlign: TextAlign.center,
),
actions: <Widget>[
IconButton(
icon: Icon(Icons.auto_awesome),
onPressed: () {
setState(() {
_dark = !_dark;
});
},
)
],
),
body: Stack(fit: StackFit.expand, children: <Widget>[
SingleChildScrollView(
//padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Stack(
children: <Widget>[
Align(
alignment: Alignment.center,
child: Text(
userSettings.nick,
textScaleFactor: 4,
style: TextStyle(
color: _dark
? Colors.white
: Colors.purple[500],
//fontWeight: FontWeight.w500,
),
)),
const SizedBox(height: 50.0),
],
),
Stack(
children: <Widget>[
Align(
alignment: Alignment.center,
child: Container(
// width: 200,
// height: 200,
child: CircleAvatar(
radius: 100.0,
backgroundImage:
//NetworkImage(user.photoURL),
NetworkImage(
userSettings.pictureUrl),
),
),
),
],
),
//const SizedBox(height: 20.0),
if (options == true) ...[
//SettingsEdit(),
//NickChange(),
ImageInput(),
],
const SizedBox(height: 10.0),
Card(
elevation: 4.0,
margin: const EdgeInsets.fromLTRB(
32.0, 8.0, 32.0, 16.0),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(10.0)),
child: Column(
children: <Widget>[
ListTile(
leading: Icon(
Icons.account_box,
color: Colors.purple,
),
title: Text("Change Nickname"),
trailing:
Icon(Icons.keyboard_arrow_right),
onTap: () {
//open change nick
//changeNick();
},
),
_buildDivider(),
ListTile(
leading: Icon(
Icons.add_a_photo,
color: Colors.purple,
),
title: Text("Change Photo"),
trailing:
Icon(Icons.keyboard_arrow_right),
onTap: () {
//open change photo
//changePhoto();
},
),
_buildDivider(),
ListTile(
leading: Icon(
Icons.lock_rounded,
color: Colors.purple,
),
title: Text("Change Password"),
trailing:
Icon(Icons.keyboard_arrow_right),
onTap: () {
//open change password
//changePassword();
},
),
_buildDivider(),
ListTile(
leading: Icon(
Icons.location_on,
color: Colors.purple,
),
title: Text("Change Your Location"),
trailing:
Icon(Icons.keyboard_arrow_right),
onTap: () {
//open change location
},
),
],
),
),
const SizedBox(height: 20.0),
]))
])));
}
return Scaffold();
}));
}
debug console
settings where I use theme now
Do you know how to avoid this null in initState? I am trying to change theme of the app and I am taking that from Firebase document whick I created when the user registered. Than I will be changing it in user settings and also want to use it(this theme) in whole app.
Thanks for help
InitState is not async (meaning execution doesn't wait for your firebase call to complete). This means that your view will be rendered before you assign _dark a value.
If you want to wait until that call is complete, use something called FutureBuilder.
In Flutter I want to create an app bar that looks as follows:
I've easily managed to add the 2 icons on the left and right, but I am struggling to create a rectangle in the middle.
I've tried the following code:
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
leading: IconButton(
icon: Image.asset('assets/images/maps.png'),
onPressed: () => {},
),
title: Expanded( // The bit that's not working. A rectangle that fills the middle area.
child: Container(
color: Colors.blue,
),
),
actions: <Widget>[
IconButton(
icon: Image.asset('assets/images/search.png'),
onPressed: () => {},
),
],
),
);
but I get the following exception:
Expanded widgets must be placed inside Flex widgets.
Expanded(no depth, flex: 1, dirty) has no Flex ancestor at all.
Thanks for the help.
You can achieve this by setting the centerTile attribute of the AppBar to true
Like this
import 'package:flutter/material.dart';
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
centerTitle: true,
leading: IconButton(
icon: Icon(
Icons.location_on,
color: Colors.grey,
),
onPressed: () => {},
),
title: Container(
padding: EdgeInsets.all(10),
child: Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Icon(Icons.refresh),
Expanded(
child: Center(
child: Text("London"),
),
),
Opacity(child: Icon(Icons.refresh), opacity: 0,),
],
),
decoration: BoxDecoration(
color: Colors.grey, borderRadius: BorderRadius.circular(10)),
),
actions: <Widget>[
IconButton(
icon: Icon(
Icons.search,
color: Colors.grey,
),
onPressed: () => {},
),
],
),
);
}
}
The output:
An alternative solution (inspired by #Josteve Adekanbi answer), to create a rectangle that fills the title area is:
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
leading: ...
title: Container(
width: double.infinity,
height: 40,
child: Container(
color: Colors.blue,
),
),
actions: ...
),
);