I use bottomNavigationBar in main page and I have 3 different page.
My screens
final List<Widget> screens = [
findLocation(),
otherPage(),
profilePage(),
];
and my wigdet build like this
return Scaffold(
body: PageStorage(
child: currentScreen,
bucket: bucket,
),
floatingActionButton: showFab?GestureDetector(
onTap: () {
setState(() {
currentScreen =
findLocation(); // if user taps on this location tab will be active
currentTab = 0;
});
},
Find location page like this
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Color(0xFF0B75E0), // background
onPrimary: Colors.white,
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.only(
right: 25.0, left: 15, top: 12, bottom: 10),
child: Text(
'Konum Bul',
textAlign: TextAlign.center,
style: TextStyle(
color: Color.fromRGBO(255, 255, 255, 1),
fontSize: 23,
letterSpacing: 1.5,
fontWeight: FontWeight.w500,
height: 1),
),
),
Icon(
Icons.arrow_forward,
color: Colors.white,
)
],
),
onPressed: () {
Navigator.push(context,
new MaterialPageRoute(builder: (context) => new loginPage()));
},
),
When I click a button on that page while my Find Location page is open, I want a different page to open than the 3 pages in main (I have a 4th login page) but my new loginpage open different place (without bottomnavigatorbar).
I want to open this page in main like the others. I want it to be tapbar underneath. How can I do that.
If you ask about why bottomnavigatorbar not showing up in login page, the answer will be :
Because you do this code in onPressed:
Navigator.push(context,new MaterialPageRoute(builder: (context) => new loginPage()));
And this code will open a new rout.
Try to write this code in onPressed :
setState((){
currentScreen = loginPage();
});
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'm utilize o Slidable on app Flutter and put as ListTile child.
So far ok.
I'm problem is i would like when I slide it to the left the text keeps appearing on the screen, as shown in the image below.(Red == Title)
At the moment the text is hidden when I swipe, as per the image.(Red == Title)
I saw that when I swipe this attribute changes state Slidable.of(context)?.animation.isCompleted
And I also verified that in my Row title of ListTile, if I line up the title as End, the title will appear msm by swiping.
So I thought, as this Slidable.of(context)?.animation.isCompleted attribute changes state I align my Row to Start or End.
But I couldn't find a way to monitor this attribute, so that when it changes I can rebuild my Row. I tried to put it as Stream but I wasn't successful. Because it looks like it doesn't generate an event, it just changes the value.
I don't know how I could do it, if anyone has any tips...
Code:
#override
Widget build(BuildContext) {
return Slidable(
key: const ValueKey(1),
endActionPane: ActionPane(
motion: const DrawerMotion(),
children: [
SlidableAction(
onPressed: (ctx) => {
Get.to(() => const CredentialOperationScreen(),
arguments:
RouteDetailCredential(itemCredential: itemCredential))
},
backgroundColor: ConstsColors.orangeAccent,
foregroundColor: Colors.white,
icon: Icons.info_outline,
),
SlidableAction(
onPressed: (ctx) => {
Get.to(() => const CredentialOperationScreen(),
arguments:
RouteDeleteCredential(itemCredential: itemCredential))
},
backgroundColor: const Color.fromRGBO(219, 32, 32, 1),
foregroundColor: Colors.white,
icon: Icons.delete_outline,
),
],
),
child: Builder(
builder: (ctx) {
return Container(
child: _listTile(ctx),
decoration: const BoxDecoration(
border: Border(
bottom:
BorderSide(color: ConstsColors.greyColorOpacity))));
},
));
}
Widget _listTile(context) {
return ListTile(
title: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Icon(
itemCredential.icon,
color: Colors.black,
),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Text(
itemCredential.name,
style: const TextStyle(
fontFamily: 'Roboto',
fontSize: 16,
),
),
),
],
),
onTap: () => {
Slidable.of(context)?.animation.isCompleted == true
? Slidable.of(context)?.close()
: Slidable.of(context)?.openEndActionPane()
},
trailing: const Icon(Icons.check_circle_outline, color: Colors.green),
);
}
I have a row with a text saying terms of use and a button. I want to show some data but perhaps I'm not using the correct keywords. All I'm getting is how to change a text on button click.
Anyway, what should I do to let the user see the terms of use on button click?
Container(
padding: EdgeInsets.only(top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
"Terms of Use",
style: TextStyle(
color: Color(0xff18172b),
fontSize: 18,
fontFamily: "Poppins",
fontWeight: FontWeight.w400,
),
),
IconButton(
iconSize: 18,
onPressed: () {},
icon: Icon(Icons.arrow_forward_ios))
],
),
),
you can navigate to another page that hold the Terms or show modal like this :
IconButton(
iconSize: 18,
onPressed: () async {
await showDialog(
barrierColor: Colors.black12.withOpacity(.6),
context: context,
builder: (_) {
return Dialog(
elevation: 0,
backgroundColor: Colors.transparent,
child: Container(
child: Text("TERMS"),
),
);
});
},
icon: Icon(Icons.arrow_forward_ios))
I want to create a custom dialog as shown below. I am able to create a normal dialog with two buttons(the positive and negative buttons). But I searched a lot about creating custom dialog like the one shown below but in vain.
showAlertDialog(BuildContext context) {
// set up the buttons
Widget cancelButton = FlatButton(
child: Text("Cancel"),
onPressed: () {},
);
Widget continueButton = FlatButton(
child: Text("Continue"),
onPressed: () {},
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
title: Text("Action"),
content: Text("Would you like to continue learning how to use Flutter alerts?"),
actions: [
cancelButton,
continueButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
Now I want to have these buttons and the image as the children of the dialog and the icon button 'X' in the bottom to close the dialog. Any help is appreciated. I am a complete beginner in flutter.
For it, we create a custom dialog
1. Custom Dialog Content class
class CustomDialog extends StatelessWidget {
dialogContent(BuildContext context) {
return Container(
decoration: new BoxDecoration(
color: Colors.white,
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.black26,
blurRadius: 10.0,
offset: const Offset(0.0, 10.0),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min, // To make the card compact
children: <Widget>[
Image.asset('assets/images/image.jpg', height: 100),
Text(
"Text 1",
style: TextStyle(
fontSize: 24.0,
fontWeight: FontWeight.w700,
),
),
SizedBox(height: 16.0),
Text(
"Text 1",
style: TextStyle(
fontSize: 24.0,
fontWeight: FontWeight.w700,
),
),
SizedBox(height: 24.0),
Align(
alignment: Alignment.bottomCenter,
child: Icon(Icons.cancel),
),
],
),
);
}
#override
Widget build(BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
elevation: 0.0,
backgroundColor: Colors.transparent,
child: dialogContent(context),
);
}
}
2. Call Custom Dialog on Click:
RaisedButton(
color: Colors.redAccent,
textColor: Colors.white,
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return CustomDialog();
});
;
},
child: Text("PressMe"),
),
This is my dialog Code
Here is am getting an error of setstate() or MarkerneedsBuild called during the build. this overlay widget cannot be marked as needing to process of building widgets.
When I am trying to call _onAlertOtp widget it will show me this error.in the build method, i've bloc and state when my signup is successful then i have to call alert dialog. but when I am trying to do that it will show me the error. Hope you understand the question please help me.
_onAlertotp(BuildContext context) {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('Enter OTP'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height / 2.7,
width: MediaQuery.of(context).size.width,
alignment: Alignment.center,
child: ListView(
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Text(
'We have Texted and/or Emailed OTP (One Time Pin) to your registered cell phone and/ or email account. Please check and enter OTP below to activate your TUDO account.',
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 15),
textAlign: TextAlign.center,
),
),
SizedBox(
height: 5,
),
Padding(
padding: const EdgeInsets.symmetric(
vertical: 8.0, horizontal: 30),
child: PinCodeTextField(
length: 6, // must be greater than 0
obsecureText: false, //optional, default is false
shape: PinCodeFieldShape
.underline, //optional, default is underline
onDone: (String value) {
setState(() {
passcode = value;
print(value);
});
},
textStyle: TextStyle(
fontWeight: FontWeight
.bold), //optinal, default is TextStyle(fontSize: 18, color: Colors.black, fontWeight: FontWeight.bold)
onErrorCheck: (bool value) {
setState(() {
hasError = value;
});
},
shouldTriggerFucntions:
changeNotifier.stream.asBroadcastStream(),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 30.0),
child: Text(
hasError
? "*Please fill up all the cells and press VERIFY again"
: "",
style: TextStyle(
color: Colors.red.shade300, fontSize: 12),
),
),
SizedBox(
height: 20,
),
RichText(
textAlign: TextAlign.center,
text: TextSpan(
text: "Didn't receive the code? ",
style:
TextStyle(color: Colors.black54, fontSize: 15),
children: [
TextSpan(
text: " RESEND",
// recognizer: onTapRecognizer,
style: TextStyle(
color: colorStyles["primary"],
fontWeight: FontWeight.bold,
fontSize: 16))
]),
),
SizedBox(
height: 7,
),
Container(
margin: const EdgeInsets.symmetric(
vertical: 16.0, horizontal: 30),
child: ButtonTheme(
height: 50,
child: FlatButton(
onPressed: () async {
/// check the [_onData] fucntion to understand better
changeNotifier.add(Functions.submit);
// at first we will check error on the press of the button.
if (!hasError) {
_onAlertrunnigbusiness(context);
}
},
child: Center(
child: Text(
"VERIFY".toUpperCase(),
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold),
)),
),
),
decoration: BoxDecoration(
color: colorStyles["primary"],
borderRadius: BorderRadius.circular(5),
),
),
],
),
),
],
),
),
actions: <Widget>[
FlatButton(
child: Text('Regret'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
Here Is Another DIalog. which open on first dialog verify button click
_onAlertrunnigbusiness(context) {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('Are you running Business?'),
content: Container(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SizedBox(
height: 10,
),
Text(
"TUDO.App aims at Businesses bridging gaps between Business Service Providers and Consumers collaborate on unique technology platform. If you own a business, we strongly recommend, provide your business information to grow your customer base and expand your business services. Any questions? Call us #1-800-888-TUDO"),
SizedBox(
height: 10,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
FlatButton.icon(
icon: Icon(FontAwesomeIcons.arrowCircleRight),
label: Text('No'),
color: colorStyles["primary"],
textColor: Colors.white,
padding:
EdgeInsets.symmetric(vertical: 10, horizontal: 15),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
onPressed: () {
NavigationHelper.navigatetoMainscreen(context);
},
),
SizedBox(height: 10),
FlatButton.icon(
icon: Icon(FontAwesomeIcons.arrowCircleRight),
label: Text('Yes'),
color: colorStyles["primary"],
textColor: Colors.white,
padding:
EdgeInsets.symmetric(vertical: 10, horizontal: 15),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
onPressed: () {
NavigationHelper.navigatetoBspsignupcreen(context);
},
),
],
)
],
),
),
actions: <Widget>[
FlatButton(
child: Text('Close'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
And Here i am calling my dialog
#override
Widget build(BuildContext context) {
return BlocListener<SignupBloc, SignupState>(
bloc: widget._signupBloc,
listener: (
BuildContext context,
SignupState currentState,
) {
if (currentState is InSignupState) {
_countries = currentState.countries.countries;
return Container(child: content(_signupBloc, context, _countries));
}
if (currentState is SignupButtonClickedEvent) {
print('SignupButtonClickedEvent clicked');
return Container();
}
if (currentState is SignupSuccessState) {
print(
' You are awesome. you have successfully registered without confirmation');
print(currentState.signupUser.toJson());
print("Hey Otp Is opned");
if (!_isError) {
return _onAlertotp(context);
}
// NavigationHelper.navigatetoMainscreen(context);
_isLoading = false;
showAlertBox = true;
return Container(
child: content(_signupBloc, context, _countries),
);
}
if (currentState is SignupVerficationOtp) {
print('signup verficitaion otp button clicked');
return Container();
}
return Container(child: content(_signupBloc, context, _countries));
},
);
}
}
try using below code to display an alert dialog
in place of return _onAlertotp(context);
WidgetsBinding.instance.addPostFrameCallback((_) {
// show alert dialog here
_onAlertotp(context);
});
You should use a BlocListener at the root of your build method to handle events that do not return a widget (in your case the showDialog method)
Your if (currentState is SignupSuccessState) { part would be in the BlocListener and not in the BlocBuilder