half of flutter form works - flutter

for some reason the sign up allows users to enter information but the sign in section doesn't any ideas
import 'package:flutter/material.dart';
import 'package:ionicons/ionicons.dart';
import 'package:personal_fitness_app/components/widgets/input_text.dart';
class SignUpView extends StatefulWidget {
final double keyboardsize;
final AnimationController parent_controller;
final AnimationController sign_up_controller;
final VoidCallback onLoginClicked;
const SignUpView(this.keyboardsize, this.parent_controller, this.sign_up_controller, this.onLoginClicked) : super();
#override
SignUpViewState createState() => SignUpViewState(keyboardsize, parent_controller, sign_up_controller,onLoginClicked);
}
class SignUpViewState extends State<SignUpView> with SingleTickerProviderStateMixin {
final double keyboardsize;
final AnimationController parent_controller;
final AnimationController sign_up_controller;
final VoidCallback onLoginClicked;
SignUpViewState(this.keyboardsize, this.parent_controller, this.sign_up_controller, this.onLoginClicked);
#override
Widget build(BuildContext context) {
final _signUpAnimation = Tween<Offset>(begin: Offset(0,-2), end: Offset(-0,0)).animate(
CurvedAnimation(
parent: parent_controller,
curve: const Interval(0.5, 1.0, curve: Curves.fastOutSlowIn)
)
);
final _change_to_login = Tween<Offset>(begin: Offset(0,0), end: Offset(0,2)).animate(
CurvedAnimation(
parent: sign_up_controller,
curve: const Interval(0.0, 1.0, curve: Curves.fastOutSlowIn)
));
final _login_coming_in = Tween<Offset>(begin: Offset(2,0), end:Offset(0,0)).animate(
CurvedAnimation(
parent: sign_up_controller,
curve: const Interval(0.0, 1.0, curve: Curves.fastOutSlowIn)
)
);
const statusBarHeight = 24;
const marginBottom = 30;
const bottomPosition = 28;
return Stack(
alignment: Alignment.center,
children: <Widget>[
Positioned(
bottom: 0,
child: Container(
height: 50,
width: MediaQuery.of(context).size.width * .74,
decoration: BoxDecoration(
color: Theme.of(context).scaffoldBackgroundColor.withOpacity(.2),
borderRadius: BorderRadius.circular(10)
),
),
),
Positioned(
bottom: 14,
child: Container(
height: 50,
width: MediaQuery.of(context).size.width * .83,
decoration: BoxDecoration(
color: Theme.of(context).scaffoldBackgroundColor.withOpacity(.2),
borderRadius: BorderRadius.circular(10)
),
),
),
Positioned(
bottom: 28,
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight:
MediaQuery.of(context).size.height
- statusBarHeight
- keyboardsize
- marginBottom
- bottomPosition
),
child: Container(
width: MediaQuery.of(context).size.width * .9,
decoration: BoxDecoration(
color: Theme.of(context).scaffoldBackgroundColor,
borderRadius: BorderRadius.circular(10)
),
child: Stack(children: [
SlideTransition(position:_signUpAnimation,child:SingleChildScrollView(
child:Opacity(opacity:parent_controller.value,child:Container(
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 25),
child: SlideTransition(position:_login_coming_in,
child:Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
_SignInTitle(),
_Subtitle(),
SizedBox(height: 30),
_SignInForm(parent_controller),
SizedBox(height: 20),
_DontHaveAccount(parent_controller, onLoginClicked),
]
),
)
)
),
)),
SlideTransition(position:_signUpAnimation,child:SingleChildScrollView(
child:Container(
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 25),
child: SlideTransition(position:_change_to_login,
child:Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
_SignUpTitle(),
_Subtitle(),
SizedBox(height: 30),
_SignUpForm(parent_controller),
SizedBox(height: 20),
_HaveAccount(parent_controller, onLoginClicked),
]
),
)
),
)
)
],),
),
),
)
],
);
}
}
class _SignUpTitle extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Text(
'SIGN UP',
style: Theme.of(context)
.textTheme
.headline5!
.copyWith(
color: Theme.of(context).primaryColor,
fontWeight: FontWeight.bold
),
);
}
}
class _SignInTitle extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Text(
'SIGN IN',
style: Theme.of(context)
.textTheme
.headline5!
.copyWith(
color: Theme.of(context).primaryColor,
fontWeight: FontWeight.bold
),
);
}
}
class _Subtitle extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Text(
'Come on!',
style: Theme.of(context)
.textTheme
.subtitle1!
.copyWith(
color: Theme.of(context).primaryColor
),
);
}
}
class _SignUpForm extends StatelessWidget {
final AnimationController animationController;
const _SignUpForm(this.animationController);
#override
Widget build(BuildContext context) {
return Form(
child: Column(
children: <Widget>[
Column(children: <Widget>[
InputText(label: 'Username', icon: Ionicons.person),
InputText(label: 'Email Address', icon: Ionicons.phone_landscape),
InputText(label: 'Password', icon: Ionicons.key,),
SizedBox(height: 40),
_SignUpSubmitButton(),
],
),
],
)
);
}
}
class _SignInForm extends StatelessWidget {
final AnimationController animationController;
const _SignInForm(this.animationController);
#override
Widget build(BuildContext context) {
return Form(
child: Column(
children: <Widget>[
Column(children: <Widget>[
InputText(label: 'Username', icon: Ionicons.person),
InputText(label: 'Password', icon: Ionicons.key,),
SizedBox(height: 40),
_SignInSubmitButton(),
],
),
],
)
);
}
}
class _SignUpSubmitButton extends StatelessWidget {
#override
Widget build(BuildContext context) {
return RaisedButton(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(100.0)),
padding: const EdgeInsets.symmetric(vertical: 17, horizontal: 80),
onPressed: () {
print("sign up button pressed");
},
child: Text(
'SIGN UP',
style: Theme.of(context)
.textTheme
.subtitle1!
.copyWith(
color: Colors.white,
fontWeight: FontWeight.bold
),
),
color: Theme.of(context).primaryColor
);
}
}
class _SignInSubmitButton extends StatelessWidget {
#override
Widget build(BuildContext context) {
return RaisedButton(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(100.0)),
padding: const EdgeInsets.symmetric(vertical: 17, horizontal: 80),
onPressed: () {
print("sign in button pressed");
},
child: Text(
'SIGN IN',
style: Theme.of(context)
.textTheme
.subtitle1!
.copyWith(
color: Colors.white,
fontWeight: FontWeight.bold
),
),
color: Theme.of(context).primaryColor
);
}
}
class _HaveAccount extends StatelessWidget {
final AnimationController animationController;
final VoidCallback onLoginClicked;
const _HaveAccount(this.animationController, this.onLoginClicked);
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => onLoginClicked(),
child: Container(
width: double.infinity,
child: RichText(
textAlign: TextAlign.center,
text: TextSpan(
text: 'Already have an account? ',
style: Theme.of(context)
.textTheme
.subtitle1!
.copyWith(
color: Colors.grey
),
children: <TextSpan>[
TextSpan(
text: 'Sign In',
style: Theme.of(context)
.textTheme
.subtitle1!
.copyWith(
color: Theme.of(context).primaryColor,
fontWeight: FontWeight.bold
)
),
],
),
),
),
);
}
}
class _DontHaveAccount extends StatelessWidget {
final AnimationController animationController;
final VoidCallback onLoginClicked;
const _DontHaveAccount(this.animationController, this.onLoginClicked);
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => {print(animationController.value)},
child: Container(
width: double.infinity,
child: RichText(
textAlign: TextAlign.center,
text: TextSpan(
text: 'Don\'t have an account? ',
style: Theme.of(context)
.textTheme
.subtitle1!
.copyWith(
color: Colors.grey
),
children: <TextSpan>[
TextSpan(
text: 'Sign Up',
style: Theme.of(context)
.textTheme
.subtitle1!
.copyWith(
color: Theme.of(context).primaryColor,
fontWeight: FontWeight.bold
)
),
],
),
),
),
);
}
}
input_text.dart
import 'package:flutter/material.dart';
class InputText extends StatelessWidget {
final String label;
final IconData icon;
const InputText({ required this.label, required this.icon}) : super();
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(vertical: 10),
child: TextFormField(
cursorColor: Theme.of(context).primaryColor,
decoration: InputDecoration(
labelText: this.label,
fillColor: Colors.grey[200],
filled: true,
border: const OutlineInputBorder(
borderSide: BorderSide(
width: 0,
style: BorderStyle.none,
),
borderRadius: BorderRadius.all(
Radius.circular(5.0),
),
),
prefixIcon: Icon(
this.icon,
color: Theme.of(context).primaryColor,
),
),
),
);
}
}
the main problem i am having is that the already have an account goes to the sign up animation successfully but the dont have an acccount button doesnt work neither does the input fields and the button. all help is appreciated

Related

Flutter TabController late initializer

I am creating an app and I am working on the profile setup and am using a tabcontroller. I have my tabcontroller working to navigate my first 3 screens, but for some reason I get a "late initializtion" error for my last screen. I have a custom button that I use for each screen, and the error gets shown once I add the custom button to my last acrren. Could someone explain to me what I need to do to get it working for my last screen? I've attached my code for the tabcontroller, custom button, and my last screen:
Tabcontroller onboarding model:
class AccountOnboarding extends StatefulWidget {
const AccountOnboarding({Key? key}) : super(key: key);
#override
State<AccountOnboarding> createState() => _AccountOnboardingState();
}
class _AccountOnboardingState extends State<AccountOnboarding> {
static const List<Tab> tabs = <Tab>[
Tab(text: 'Name'),
Tab(text: 'Age and Profile'),
Tab(text: 'Bio and Interests'),
Tab(text: 'Selection')
];
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: tabs.length,
child: Builder(builder: (BuildContext context) {
final TabController tabController = DefaultTabController.of(context)!;
tabController.addListener(() {
if (!tabController.indexIsChanging) {}
});
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: const Color(0xff31708c),
appBar: AppBar(
automaticallyImplyLeading: false,
backgroundColor: Colors.transparent,
elevation: 0,
title: Row(
children: [
Expanded(
child: Image.asset('assets/images/Logo_Strength.png',
height: 50),
),
Expanded(
flex: 2,
child: RichText(
text: TextSpan(
style: GoogleFonts.montserrat(
fontSize: 30),
children: <TextSpan> [
TextSpan(text: 'Stren',
style: GoogleFonts.montserrat(
color: Colors.white,
fontWeight: FontWeight.bold,
letterSpacing: 1,
shadows: [
Shadow(
color: Colors.black.withOpacity(0.7),
offset: const Offset(1.5, 0.0))
])),
TextSpan(text: ';',
style: GoogleFonts.montserrat(
color: const Color(0xffef6a7a), fontWeight: FontWeight.bold,
letterSpacing: 1,
shadows: [
Shadow(
color: Colors.black.withOpacity(0.7),
offset: const Offset(1.5, 0.0))
])),
TextSpan(text: 'th',
style: GoogleFonts.montserrat(
color: Colors.white,
fontWeight: FontWeight.bold,
letterSpacing: 1,
shadows: [
Shadow(
color: Colors.black.withOpacity(0.7),
offset: const Offset(1.5, 0.0))
]))
],
),
),
),
],
)
),
body: TabBarView(
// physics: const NeverScrollableScrollPhysics(),
children: [
NamePage(tabController: tabController,),
ageAndPicture(tabController: tabController,),
bioAndInterests(tabController: tabController,),
SelectionPage(tabController: tabController,)
],
),
);
}));
}}
Custom Button:
class CustomButton extends StatelessWidget {
final TabController tabController;
const CustomButton({Key? key,
required this.tabController})
: super(key: key);
#override
Widget build(BuildContext context) {
return DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
color: Colors.white
),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(
vertical: 16),
elevation: 0,
primary: Colors.transparent
),
onPressed: () {
tabController.animateTo(tabController.index + 1);
},
child: Container(
width: double.infinity,
child: Center(
child: Text('Continue',
style: GoogleFonts.montserrat(
color: const Color.fromARGB(255, 20, 83, 106),
fontSize: 19,
fontWeight: FontWeight.w600
),),
),
)
),
);
}
}
Last Screen code:
class SelectionPage extends StatefulWidget {
final TabController tabController;
const SelectionPage({Key? key,
required this.tabController}) : super(key: key);
#override
_SelectionPageState createState() => _SelectionPageState();
}
class _SelectionPageState extends State<SelectionPage>{
List <Item>listOfModel = [];
late TabController tabController;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
String retrieveString;
final data = ModalRoute.of(context)!.settings;
if (data.arguments == null) {
retrieveString = "empty";
} else {
retrieveString = data.arguments as String;
}
listOfModel.add(Item(title: "Maintaining healthy relationships"));
listOfModel.add(Item(title: "Stress and anxiety management"));
listOfModel.add(Item(title: "Maintaing a better work-life balance"));
listOfModel.add(Item(title: "Personal growth and development"));
listOfModel.add(Item(title: "Being happier and more content in life"));
listOfModel.add(Item(title: "Mental and emotional well-being"));
double _height = MediaQuery.of(context).size.height;
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: const Color(0xff31708c),
body: Padding(
padding: EdgeInsets.only(
left: 30,
right: 30,
top: _height * 0.07,
bottom: _height * 0.05),
child: Column(
children: [
Column(
children: [
Column(
children: <Widget>[
Text('Hello there $retrieveString! What all would you like to focus on?',
style: GoogleFonts.montserrat(
color: Colors.white70,
fontSize: 19,
fontWeight: FontWeight.w600
),
textAlign: TextAlign.center,),
const SizedBox(height: 10),
Text("You can pick all that apply:",
style: GoogleFonts.montserrat(
color: Colors.white70,
fontSize: 14.5,
fontWeight: FontWeight.w600
),),
const SizedBox(height: 15,),
GridView.count(
primary: true,
shrinkWrap: true,
padding: const EdgeInsets.all(10),
childAspectRatio: 1.15,
crossAxisCount: 2,
crossAxisSpacing: 25,
mainAxisSpacing: 25,
children: [
gridItem(listOfModel[0],MyFlutterApp.relationships),
gridItem(listOfModel[1],MyFlutterApp2.meditate),
gridItem(listOfModel[2],MyFlutterApp.balance),
gridItem(listOfModel[3],MyFlutterApp2.personal_growth),
gridItem(listOfModel[4],MyFlutterApp.happy),
gridItem(listOfModel[5],MyFlutterApp3.well_rounded),
],
),
const SizedBox(height: 18,),
],
),
CustomButton(tabController: tabController)
],
),
],
),
),
);
}
Widget gridItem(Item item, IconData icon){
return GestureDetector(
onTap: () {
setState(() {
item.isSelected = !item.isSelected;
});
},
child: Stack(
children: [Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
border: Border.all(
color: const Color.fromARGB(255, 20, 83, 106),
width: 2.5),
color: item.isSelected ? Color.fromARGB(255, 234, 188, 193) : Colors.white
),
child: Column(
children: [
Align(alignment: Alignment.topCenter,
child: Icon(
icon,
color: const Color(0xff31708c),
size: 45,
),
),
const SizedBox(height: 4,),
Text(item.title,
style: GoogleFonts.montserrat(
fontSize: 14,
fontWeight: FontWeight.w500,
color: const Color(0xff31708c)
),
textAlign: TextAlign.center,),
],
),
),
Positioned(
top: 0,
right: 0,
child: Offstage(
offstage: !item.isSelected,
child: Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(width: 2.5),
shape: BoxShape.circle),
child: const Icon(
Icons.check,
color: Colors.green,
),
),
),
)
],
)
);
}
}
class Item{
String title;
bool isSelected;
Item({required this.title, this.isSelected = false});
}
Remove
late TabController tabController;
in SelectionPage and change
CustomButton(tabController: tabController)
in SelectionPage to
CustomButton(tabController: widget.tabController)

Display TickMark widget depending on String and boolean value in Dart

Need to display icon with checkmark based on a String value that comes dynamically.
Like
this image is its pending show first widget with tick and rest are blank.
if delivered show with tick and the rest are blank.
Facing problems in creating logic using enums.
Currently, it displays the icons on button clicks
based on four constants which is fine with the widget CheckStatus.
Need to make in a way based on a boolean check if it's true and pending that pending tick widget displayed
and similar with other values.
Here is the complete code for it currently.
import 'package:dotted_border/dotted_border.dart';
import 'package:dotted_line/dotted_line.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:matab/models/order.dart';
import 'package:matab/ui/general_widgets/check_status.dart';
import 'package:matab/ui/pages/styles.dart';
import '../../general_widgets/custom_gradient_button.dart';
class TrackOrder extends StatefulWidget {
const TrackOrder({Key? key, required this.order}) : super(key: key);
final Order order;
#override
State<TrackOrder> createState() => _TrackOrderState();
}
enum Status { Pending, Confirmed, Shipped, Received }
class _TrackOrderState extends State<TrackOrder> {
static const darkGreyColor = Colors.grey;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Center(child: Text('Track Order')),
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () => Get.back(),
),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
const SizedBox(height: 50),
Text(
"Order ID:" + widget.order.orderID,
style: const TextStyle(
color: darkGreyColor,
fontSize: 18,
fontWeight: FontWeight.bold),
),
const SizedBox(height: 50),
const Text('Sat, 12 Mar 2022',
style: TextStyle(
color: darkGreyColor,
fontSize: 18,
fontWeight: FontWeight.bold)),
const SizedBox(
height: 15,
),
Container(
margin: const EdgeInsets.fromLTRB(15, 0, 0, 0),
child: const Text('Estimated Time: 07 Days',
style: TextStyle(fontSize: 23, fontWeight: FontWeight.bold)),
),
const SizedBox(height: 30),
SizedBox(
width: 200,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
OrderStatusBar(title: widget.order.orderStatus, status: true),
dottedLine(),
OrderStatusBar(
title: widget.order.orderStatus, status: false),
dottedLine(),
OrderStatusBar(
title: widget.order.orderStatus, status: false),
dottedLine(),
OrderStatusBar(
title: widget.order.orderStatus, status: false),
],
),
),
const SizedBox(
height: 40,
),
Container(
margin: const EdgeInsets.fromLTRB(15, 0, 0, 0),
child: const Text('Shipping Address',
style: TextStyle(fontSize: 23, fontWeight: FontWeight.bold)),
),
Center(
child: Text(widget.order.deliveryAddress.address,
style: const TextStyle(
color: Colors.grey,
fontSize: 18,
fontWeight: FontWeight.bold)),
),
Center(
child: Padding(
padding: const EdgeInsets.all(
50.0,
),
child: CustomGradientButton(
buttonText: "Track Order".tr, buttonFunction: () => {}),
),
),
Center(
child: Padding(
padding: const EdgeInsets.only(top: 18.0),
child: GestureDetector(
child: Text(
'Back to Home'.tr,
style: TextStyle(
color: mainColor,
fontSize: 23,
fontWeight: FontWeight.bold),
),
onTap: () => {
Get.off(CheckStatus(
order: widget.order,
))
},
),
),
)
],
),
),
);
}
}
class OrderStatusBar extends StatefulWidget {
const OrderStatusBar({Key? key, required this.title, required this.status})
: super(key: key);
final String title;
final bool status;
#override
State<OrderStatusBar> createState() => _OrderStatusBarState();
}
class _OrderStatusBarState extends State<OrderStatusBar> {
#override
Widget build(BuildContext context) {
return Directionality(
textDirection: TextDirection.rtl,
child: Row(
children: [
widget.status ? dottedCircleWithCheckMark() : dottedCircle(),
const SizedBox(width: 30),
Text(
widget.title.tr,
style: TextStyle(
fontSize: 20,
fontWeight: widget.status ? FontWeight.bold : null,
),
),
],
),
);
}
}
const size = 25.0;
const strokeWidth = 1.0;
const checkedColor = Color.fromRGBO(232, 113, 65, 1);
Widget dottedLine() {
return Directionality(
textDirection: TextDirection.rtl,
child: Align(
alignment: Alignment.topRight,
child: Container(
margin: const EdgeInsets.fromLTRB(0, 0, size / 2, 0),
child: const Padding(
padding: EdgeInsets.only(left: 27 / 2),
child: SizedBox(
height: size,
child: DottedLine(
dashColor: Colors.black,
direction: Axis.vertical,
lineLength: size,
lineThickness: strokeWidth,
dashLength: 5,
dashGapLength: 5,
),
),
),
),
),
);
}
dottedCircle() {
return DottedBorder(
borderType: BorderType.Circle,
dashPattern: const [5, 5],
child: Container(
height: size,
width: size,
decoration: const BoxDecoration(shape: BoxShape.circle),
));
}
dottedCircleWithCheckMark() {
return Container(
height: size + strokeWidth * 2,
width: size + strokeWidth * 2,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: checkedColor,
),
child: const Icon(
Icons.check,
color: Colors.white,
size: size / 4 * 3,
),
);
}
// ignore_for_file: constant_identifier_names
class CheckStatus extends StatefulWidget {
const CheckStatus({Key? key, required this.order}) : super(key: key);
final Order order;
#override
State<CheckStatus> createState() => _CheckStatusState();
}
class _CheckStatusState extends State<CheckStatus> {
int selectedItemIndex = 0;
var pending = Status.Pending;
List<bool> orderStatus = [true,true,true,false];
#override
void initState() {
// TODO: implement initState
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
for (int i = 0; i < Status.values.length; i++)
ElevatedButton(
onPressed: () {
selectedItemIndex = i;
setState(() {});
},
child: Text("Order Status ${Status.values[i]}"),
),
Row(
children: [
for (int i = 0; i <= selectedItemIndex; i++)
Container(
height: size + strokeWidth * 2,
width: size + strokeWidth * 2,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: checkedColor,
),
child: const Icon(
Icons.check,
color: Colors.white,
size: size / 4 * 3,
),
),
ElevatedButton(onPressed: () {}, child: Text("Back"))
],
)
],
),
);
}
}

Why do I get a huge grey circle in the background of scaffold?

I have a PayBills() widget screen = that has 2 tabs which each display a separate tab dart file which I've specified, but I get a huge grey circle in the background of the first dart file and I get nothing in the second tab, but I don't know where the issue is.
PayBills() widget screen code :
import 'package:flutter/material.dart';
import '../../constans/constants.dart';
import 'first_tab.dart';
import 'second_tab.dart';
class PayBills extends StatefulWidget {
#override
_PayBillsState createState() => _PayBillsState();
}
class _PayBillsState extends State<PayBills>
with SingleTickerProviderStateMixin {
TabController _controller;
#override
void initState() {
super.initState();
_controller = TabController(vsync: this, length: 2);
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.white,
centerTitle: true,
elevation: 0,
title: Text(
'تسديد فاتورة',
style: TextStyle(
color: leaderLogo,
fontSize: 24,
fontFamily: 'Calibri',
),
),
bottom: TabBar(
controller: _controller,
tabs: [
Tab(
child: Text(
'فواتير مستحقة',
style: TextStyle(
fontFamily: 'Calibri',
fontSize: 14,
color: Colors.black,
),
),
),
Tab(
child: Text(
'فواتير مدفوعة',
style: TextStyle(
fontFamily: 'Calibri',
fontSize: 14,
color: Colors.black,
),
),
),
],
),
),
body: TabBarView(
controller: _controller,
children: [
PayBillsList(),
SecondTab(),
],
));
}
}
first_tab widget code :
import 'package:flutter/material.dart';
import '../../constans/constants.dart';
class BillDetails extends StatelessWidget {
final String billName;
final String billImage;
final String billDate;
const BillDetails({Key key, this.billName, this.billImage, this.billDate})
: super(key: key);
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(
top: 20,
right: 5,
left: 5,
),
width: 378,
height: 93,
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey,
),
borderRadius: BorderRadius.circular(5),
),
child: ListTile(
leading: CircleAvatar(
backgroundImage: AssetImage(billImage),
backgroundColor: Colors.white,
),
title: Text(
billName,
style: TextStyle(
fontFamily: 'Calibri',
fontSize: 16,
color: Colors.black,
),
),
subtitle: Text(
billDate,
style: TextStyle(
fontFamily: 'Calibri',
fontSize: 12,
color: Colors.black,
),
),
trailing: RaisedButton(
color: raisedButtonColor,
onPressed: () {},
child: Text(
"دفع",
style: TextStyle(
color: Colors.white,
),
),
),
));
}
}
class PayBillsList extends StatelessWidget {
final List<BillDetails> billsList = [
BillDetails(
billName: 'فاتورة كهرباء',
billImage: 'assets/images/electricity.png',
billDate: '30 / 4 / 2020',
),
BillDetails(
billName: 'فاتورة مياه',
billImage: 'assets/images/water.png',
billDate: '30 / 4 / 2020',
),
];
#override
Widget build(BuildContext context) {
return Container(
width: 378,
height: 93,
decoration: BoxDecoration(
border: Border.all(
width: 1,
color: Colors.grey,
),
shape: BoxShape.circle,
),
child: ListView.builder(
itemBuilder: (context, index) {
return BillDetails(
billName: billsList.elementAt(index).billName,
billImage: billsList.elementAt(index).billImage,
billDate: billsList.elementAt(index).billDate,
);
},
shrinkWrap: true,
itemCount: billsList.length,
scrollDirection: Axis.vertical,
),
);
}
}
class PayButton extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ButtonTheme(
minWidth: 20,
height: 20,
child: RaisedButton(
onPressed: () {},
color: raisedButtonColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
child: Center(
child: Text(
//Login button text properties
'دفع',
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontFamily: 'Calibri',
)),
),
),
);
}
}
You used a circle shape for BoxDecoration. Comment this line:
shape: BoxShape.circle,
Container(
width: 378,
height: 93,
decoration: BoxDecoration(
border: Border.all(
width: 1,
color: Colors.grey,
),
// shape: BoxShape.circle,
),

Flutter web, update navbar after authorization

I am trying to create a web application using flutter and I have a question. After I go through authorization, I need to change the "login" button in the navbar, as I understand it, I need to change the button text and call setState in my navbar, but in my implementation an exception is thrown.
AuthPage.dart
import 'package:flutter/material.dart';
import 'package:um/pages/home/app_color.dart';
import 'package:um/scripts/api_client.dart';
import 'package:um/scripts/locator.dart';
import 'NavBarDesktop.dart';
class AuthorizationPageDesktop extends StatefulWidget {
AuthorizationPageDesktop({Key key}) : super(key: key);
#override
_AuthorizationPageDesktopState createState() =>
_AuthorizationPageDesktopState();
}
class _AuthorizationPageDesktopState extends State<AuthorizationPageDesktop> {
TextEditingController _emailController = TextEditingController();
TextEditingController _passwordController = TextEditingController();
bool rememberMe = false;
ApiClient apiClient = ApiClient.getInstance();
ScrollController _scrollController = ScrollController();
PageController _pageController = PageController();
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Container(
child: Padding(
padding: EdgeInsets.only(top: 150, left: 0, right: 0),
child: Column(
children: <Widget>[
Text(
'Авторизация',
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 28,
color: textPrimaryColor),
),
SizedBox(
height: 40,
),
_input(Icon(Icons.mail), 'Email', _emailController, false, 15),
SizedBox(
height: 15,
),
_input(Icon(Icons.lock), 'Password', _passwordController, true, 15),
SizedBox(
height: 5,
),
Container(
padding: EdgeInsets.only(left: 20, right: 20),
width: 460,
child: Theme(
data: ThemeData(
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
hoverColor: Colors.transparent),
child: CheckboxListTile(
title: Text(
'Запомнить меня',
style: TextStyle(color: textPrimaryColor),
),
value: rememberMe,
onChanged: (bool value) {
setState(() {
rememberMe = value;
});
},
))),
SizedBox(
height: 5,
),
_button('Войти', auth, 15),
SizedBox(
height: 15,
),
Container(
width: 460,
child: Align(
alignment: Alignment.bottomCenter,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Пройдите ',
style: TextStyle(color: Colors.white, fontSize: 12),
),
Text(
'регистрацию, ',
style: TextStyle(color: linkColor, fontSize: 12),
),
Text(
'если вы этого еще не сделали',
style: TextStyle(color: Colors.white, fontSize: 12),
),
],
)),
),
SizedBox(height: 50),
],
),
)));
}
Widget _input(Icon icon, String hint, TextEditingController controller,
bool obscure, double borderRadius) {
return Container(
width: 460,
height: 50,
padding: EdgeInsets.only(left: 20, right: 20),
child: TextField(
controller: controller,
obscureText: obscure,
style: TextStyle(fontSize: 16, color: Colors.white),
decoration: InputDecoration(
border: OutlineInputBorder(),
isDense: true, // Added this
contentPadding: EdgeInsets.all(8), //
hintStyle: TextStyle(
fontWeight: FontWeight.bold, fontSize: 16, color: Colors.white),
hintText: hint,
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(borderRadius),
borderSide: BorderSide(color: Colors.white, width: 2)),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(borderRadius),
borderSide: BorderSide(color: Colors.white54, width: 1)),
prefixIcon: Padding(
padding: EdgeInsets.only(left: 10, right: 10),
child: IconTheme(
data: IconThemeData(color: Colors.white),
child: icon,
),
)),
),
);
}
Widget _button(String label, void func(), double borderRadius) {
return Container(
width: 460,
padding: EdgeInsets.only(left: 20, right: 20),
child: RaisedButton(
onPressed: () {
apiClient
.authorization(_emailController.text, _passwordController.text)
.then((value) {
func();
});
},
highlightColor: Theme.of(context).primaryColor,
color: buttonPrimaryColor,
child: Text('Войти',
style: TextStyle(
fontWeight: FontWeight.bold,
color: textPrimaryColor,
fontSize: 16)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(borderRadius)),
));
}
void auth() {
var state = navBar<NavBarDesktop>().navBarState;
state.update();
}
}
NavBar.dart
import 'package:flutter/material.dart';
import 'package:um/Widgets/Desktop/AuthPageDesktop.dart';
import 'package:um/Widgets/Desktop/HomePageDesktop.dart';
import 'package:um/Widgets/NavBarItem.dart';
import 'package:um/layout_template/layout_template.dart';
import 'package:um/pages/home/app_color.dart';
import 'package:um/scripts/api_client.dart';
import 'package:um/scripts/locator.dart';
class NavBarDesktop extends StatefulWidget {
NavBarDesktop({Key key}) : super(key: key);
GlobalKey<_NavBarDesktopState> navBarDesktop =
GlobalKey<_NavBarDesktopState>();
_NavBarDesktopState navBarState = new _NavBarDesktopState();
static _NavBarDesktopState of(BuildContext context) {
// print('_NavBarDesktopState -> ${context}');
assert(context != null);
final _NavBarDesktopState result =
// ignore: deprecated_member_use
context.ancestorStateOfType(const TypeMatcher<_NavBarDesktopState>());
// print('_NavBarDesktopState resutl -> ${result}');
return result;
}
#override
_NavBarDesktopState createState() => new _NavBarDesktopState();
}
class _NavBarDesktopState extends State<NavBarDesktop> {
String authButtonTitle = "Войти";
#override
void initState() {
print('call init state navbar ${ApiClient.username}');
if (ApiClient.username != null && ApiClient.username.length > 0)
authButtonTitle = ApiClient.username;
super.initState();
}
void update() {
setState(() {
authButtonTitle = ApiClient.username;
});
}
#override
Widget build(BuildContext context) {
return new Container(
color: primaryColor,
height: 50,
padding: EdgeInsets.only(left: 50, right: 50),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
onTap: () {
LayoutTemplate.of(context).change_page(HomePageDesktop());
},
child: Text(
'UM',
textAlign: TextAlign.center,
style: TextStyle(
color: textPrimaryColor,
fontWeight: FontWeight.w600,
fontSize: 40),
)),
NavBarItem(
authButtonTitle,
() => LayoutTemplate.of(context)
.change_page(AuthorizationPageDesktop())),
],
),
);
}
void auth_page_up(BuildContext context) {
LayoutTemplate.of(context).change_page(AuthorizationPageDesktop());
}
}
Exception
Error: setState() called in constructor: _NavBarDesktopState#5e1ee(lifecycle state: created, no widget, not mounted)
This happens when you call setState() on a State object for a widget that hasn't been inserted into the widget tree yet. It is not necessary to
call setState() in the constructor, since the state is already assumed to be dirty when it is initially created.
at Object.throw_ [as throw] (http://localhost:50572/dart_sdk.js:4334:11)
at http://localhost:50572/packages/flutter/src/widgets/widget_span.dart.lib.js:13615:23
at NavBarDesktop._NavBarDesktopState.new.setState (http://localhost:50572/packages/flutter/src/widgets/widget_span.dart.lib.js:13618:26)
at NavBarDesktop._NavBarDesktopState.new.update (http://localhost:50572/packages/um/scripts/router.dart.lib.js:1717:12)
at AuthPageDesktop._AuthorizationPageDesktopState.new.auth (http://localhost:50572/packages/um/scripts/router.dart.lib.js:1932:13)
at http://localhost:50572/packages/um/scripts/router.dart.lib.js:1926:15
at _RootZone.runUnary (http://localhost:50572/dart_sdk.js:37457:58)
at _FutureListener.then.handleValue (http://localhost:50572/dart_sdk.js:32441:29)
at handleValueCallback (http://localhost:50572/dart_sdk.js:32988:49)
at Function._propagateToListeners (http://localhost:50572/dart_sdk.js:33026:17)
at _Future.new.[_completeWithValue] (http://localhost:50572/dart_sdk.js:32869:23)
at async._AsyncCallbackEntry.new.callback (http://localhost:50572/dart_sdk.js:32891:35)
at Object._microtaskLoop (http://localhost:50572/dart_sdk.js:37718:13)
at _startMicrotaskLoop (http://localhost:50572/dart_sdk.js:37724:13)
at http://localhost:50572/dart_sdk.js:33243:9
Your _NavBarDesktopState global key needs to be initialized in your _NavBarDesktopState class., not the NavBarDesktop class. It's trying to set the global key before the state has even been created.
class NavBarDesktop extends StatefulWidget {
NavBarDesktop({Key key}) : super(key: key);
_NavBarDesktopState navBarState;
static _NavBarDesktopState of(BuildContext context) {
assert(context != null);
final _NavBarDesktopState result =
// ignore: deprecated_member_use
context.ancestorStateOfType(const TypeMatcher<_NavBarDesktopState>());
return result;
}
#override
_NavBarDesktopState createState() {
navBar.registerLazySingleton(() => this);
navBarState = _NavBarDesktopState();
return navBarState;
}
}

Why does a change in state of a child bottom sheet trigger a rebuild of parent widget?

I have a Scaffold screen (ListsScreen).
Which has a Button(AddNewListButton) that opens up a Modal Bottom Sheet (ListScreenBottomSheetWidget).
Bottom Sheet has TextField (ListTitleInputTextFieldWidget).
When i tap the TextField to open the keyboard, the parent screen rebuilds itself, due to which ofcourse all its child widgets are rebuilt as well.
Why is this happening? I was under the impression that state changes only rebuild themselves or their children, not their parents. And i also added const constructors almost everywhere to avoid rebuilds but this is still happening.
The Parent ListsScreen:
class ListsScreen extends StatelessWidget {
const ListsScreen();
static const routeName = '/lists-screen';
#override
Widget build(BuildContext context) {
final user = Provider.of<AuthProvider>(context, listen: false).getUser;
print('stateless rebuilding');
return Scaffold(
appBar: AppBar(
centerTitle: false,
title: Text(
'${user['name']}\'s Lists',
style: TextStyle(
color: Theme.of(context).primaryColorLight,
),
),
actions: <Widget>[
const SignOutButton(),
],
),
body: Center(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: <Widget>[
SizeConfig.smallDevice
? const SizedBox(
height: 30,
)
: const SizedBox(
height: 40,
),
SizeConfig.smallDevice
? Text(
'Welcome to TODOS',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20,
color: Colors.grey[700],
),
)
: Text(
'Welcome to TODOS',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 25,
color: Colors.grey[700],
),
),
SizeConfig.smallDevice
? const SizedBox(
height: 30,
)
: const SizedBox(
height: 40,
),
const AddNewListButton(),
SizeConfig.smallDevice
? const SizedBox(
height: 30,
)
: const SizedBox(
height: 40,
),
const UserListsListViewWidget(),
],
),
),
),
);
}
}
class SignOutButton extends StatelessWidget {
const SignOutButton();
Future<void> _submitRequest(BuildContext context) async {
_showLoadingAlert(context);
try {
await Provider.of<AuthProvider>(context, listen: false)
.submitLogOutRequest();
Navigator.of(context).pop();
Navigator.of(context).pushReplacementNamed(LoginScreen.routeName);
} on HttpExceptions catch (error) {
Navigator.of(context).pop();
_showErrorDialogue(error.getErrorList, context);
}
}
void _showErrorDialogue(List<dynamic> errorMessages, BuildContext context) {
showDialog(
context: context,
builder: (ctx) => Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
child: ErrorListWidget(errorMessages: errorMessages),
),
);
}
void _showLoadingAlert(BuildContext context) {
showDialog(
context: context,
builder: (ctx) => const LoadingWidget(),
);
}
#override
Widget build(BuildContext context) {
return FlatButton(
onPressed: () => _submitRequest(context),
child: Row(
children: <Widget>[
Text(
'Sign Out',
style: TextStyle(
color: Theme.of(context).primaryColorLight,
),
),
Icon(
Icons.exit_to_app,
color: Theme.of(context).primaryColorLight,
),
],
),
);
}
}
class AddNewListButton extends StatelessWidget {
const AddNewListButton();
void _modalBottomSheetMenu(BuildContext context) {
showModalBottomSheet(
context: context,
backgroundColor: Colors.transparent,
isScrollControlled: true,
builder: (builder) {
return const ListScreenBottomSheetWidget();
},
);
}
#override
Widget build(BuildContext context) {
return RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
elevation: 10,
color: Theme.of(context).primaryColor,
onPressed: () => _modalBottomSheetMenu(context),
child: Text(
'+ Add List',
style: TextStyle(
color: Colors.white,
fontSize: SizeConfig.smallDevice ? 10 : 15,
),
),
);
}
}
The Modal Bottom Sheet:
import 'package:flutter/material.dart';
import 'package:todo_spicotech/helpers/size_config.dart';
class ListScreenBottomSheetWidget extends StatelessWidget {
const ListScreenBottomSheetWidget();
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus();
}
currentFocus.unfocus();
},
child: Container(
margin: const EdgeInsets.all(20.0),
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom,
),
child: Material(
borderRadius: BorderRadius.all(Radius.circular(15)),
elevation: 10,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SizeConfig.smallDevice
? Text(
'Create a new List',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20,
color: Colors.grey[700],
),
)
: Text(
'Create a new List',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 25,
color: Colors.grey[700],
),
),
SizeConfig.smallDevice
? const SizedBox(
height: 20,
)
: const SizedBox(
height: 30,
),
const ListTitleInputTextFieldWidget(),
SizeConfig.smallDevice
? const SizedBox(
height: 20,
)
: const SizedBox(
height: 30,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
InkWell(
borderRadius: BorderRadius.circular(5),
onTap: () {
Navigator.of(context).pop();
},
child: Ink(
padding: EdgeInsets.all(10),
child: const Text('CANCEL'),
),
),
RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
elevation: 10,
color: Theme.of(context).primaryColor,
onPressed: () {},
child: Text(
'Create',
style: TextStyle(
color: Colors.white,
fontSize: SizeConfig.smallDevice ? 10 : 15,
),
),
),
],
),
],
),
),
),
),
);
}
}
class ListTitleInputTextFieldWidget extends StatefulWidget {
const ListTitleInputTextFieldWidget();
#override
_ListTitleInputTextFieldWidgetState createState() => _ListTitleInputTextFieldWidgetState();
}
class _ListTitleInputTextFieldWidgetState extends State<ListTitleInputTextFieldWidget> {
#override
Widget build(BuildContext context) {
return TextFormField(
decoration: const InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.lightBlue,
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.lightBlue,
),
),
labelText: 'List Title',
contentPadding: EdgeInsets.all(10),
),
);
}
}
when you call showModalBottomSheet , it actually use Navigator inside
return Navigator.of(context, rootNavigator: useRootNavigator).push(_ModalBottomSheetRoute<T>(
builder: builder,
source code of showModalBottomSheet https://github.com/flutter/flutter/blob/17079f26b54c8517678699a0cefe5f7bfec67b3f/packages/flutter/lib/src/material/bottom_sheet.dart#L635
Flutter teams' reply of issue Pages on Navigator stack rebuild when a new page is pushed https://github.com/flutter/flutter/issues/11655#issuecomment-348287396
This is working as intended. In general, you should assume that all widgets can rebuild at any time, that they don't is mostly just an optimisation.
In particular, routes will rebuild because their navigator state has changed so they might need to update how they draw back buttons and the like.