I'm trying to create a pageview that I can load a widget into that is defined in another file. This works fine, except when I try to add a callback, I get the following error:
FlutterError (setState() or markNeedsBuild() called during build.
This error is triggered when the email entered is considered to be valid (that is, when the code in the email_entry.dart calls the callback function that was passed from the account_onboarding.dart file.) I haven't been able to determine why this is happening, and no tutorials on this subject seem to exist. I am still pretty new to Dart/Flutter, so I'm hoping someone can point out what's happening (and a fix) here.
Here is my code:
-Parent widget, account_onboarding.dart
import 'package:flutter/material.dart';
import 'package:page_view_indicators/page_view_indicators.dart';
import 'package:animated_title_screen/screens/email_entry.dart';
class AccountOnboarding extends StatefulWidget {
const AccountOnboarding({Key? key}) : super(key: key);
#override
State<AccountOnboarding> createState() => _AccountOnboardingState();
}
class _AccountOnboardingState extends State<AccountOnboarding> {
final _pController = PageController(initialPage: 0);
final _currentPageNotifier = ValueNotifier<int>(0);
final List<Widget> _pages = [];
bool validEmail = false; //Callback should set this variable
#override
void initState() {
super.initState();
_pages.add( //Add the EmailEntry widget to the list
EmailEntry(emailIsValid: (p0) {
setState(() {
validEmail = p0;
});
},),
);
_pages.add(
Container(
color: Colors.blue,
child: Text("Pg2"),
),
);
_pages.add(
Container(
color: Colors.green,
child: Text("Pg3"),
),
);
}
#override
void dispose() {
_pController.dispose();
_currentPageNotifier.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"Create Account",
style: Theme.of(context).textTheme.headline5,
),
centerTitle: true,
actions: [
IconButton(
icon: const Icon(Icons.close),
onPressed: () => Navigator.pop(context),
),
],
),
body: Stack(
fit: StackFit.expand,
children: [
Column(
children: [
Row(
children: [
Text(
"Step ${_currentPageNotifier.value + 1} of ${_pages.length}",
),
CirclePageIndicator(
dotColor: const Color(0xFF323232),
selectedDotColor: const Color(0xFFE4231F),
size: 10,
selectedSize: 10,
currentPageNotifier: _currentPageNotifier,
itemCount: _pages.length,
),
],
),
PageView(
controller: _pController,
onPageChanged: (index) {
setState(() {
_currentPageNotifier.value = index;
});
},
children: [
for (Widget p in _pages) p, //Display all pages in _pages[]
],
),
ElevatedButton(
child: const Text("Continue"),
onPressed: () => print("Pressed 2"),
style: ElevatedButton.styleFrom(
primary: validEmail ? const Color(0xFFE1251B) : Colors.black,
textStyle: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 15,
),
),
),
],
),
],
),
);
}
}
Here is the email_entry.dart code:
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
class EmailEntry extends StatefulWidget {
final Function(bool) emailIsValid; //Function required in constructor
const EmailEntry({Key? key, required this.emailIsValid}) : super(key: key);
#override
State<EmailEntry> createState() => _EmailEntryState();
}
class _EmailEntryState extends State<EmailEntry> {
final _emailController = TextEditingController();
FocusNode _emailFocus = FocusNode();
#override
void initState() {
super.initState();
_emailController.addListener(() => setState(() {}));
_emailFocus.addListener(() {
print("Focus email");
});
}
#override
void dispose() {
_emailController.dispose();
super.dispose();
}
bool validateEmail(String email) {
bool valid = RegExp(
r"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+#[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?)*$")
.hasMatch(email);
if (valid) {
widget.emailIsValid(true); //Call the callback function
}
return valid;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
Column(
children: [
Text(
"YOUR EMAIL",
style: Theme.of(context).textTheme.headline2,
),
Text(
"Please use an email address that you would like to make your login.",
style: Theme.of(context).textTheme.bodyText2,
textAlign: TextAlign.center,
),
Container(
child: Text(
"Email Address",
),
),
TextField(
controller: _emailController,
keyboardType: TextInputType.emailAddress,
focusNode: _emailFocus,
suffixIcon: getTextFieldSuffix(emailController, _emailFocus), //OFFENDING CODE
),
],
),
],
),
);
}
//THIS FUNCTION CAUSED THE ISSUE. It is code I got from a youtube //tutorial. Probably should have guessed.
Widget getTextFieldSuffix(TextEditingController controller, FocusNode node) {
if (controller.text.isNotEmpty && node.hasFocus) {
return IconButton(
color: Colors.grey.withAlpha(150),
onPressed: () => controller.clear(),
icon: const Icon(Icons.close));
} else if (controller.text.isNotEmpty && !node.hasFocus) {
return const Icon(
Icons.check,
color: Colors.green,
);
}
return Container(
width: 0,
);
}
}
in initState,you need to call addPostFrameCallback.
like this...
#override
void initState() {
super.initState();
///Add This Line
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
///All of your code
});
}
I found out that there is some code in my production version that calls a redraw every time the user enters a letter into the textfield for the email address. This was causing a problem because the screen was already being redrawn, and I was calling setState to redraw it again. I will edit the code shown above to include the offending code.
Related
im trying to put the Textvalue, i have created via Texteditingcontroller into the text on the Neuigkeiten Page via controller.value, so the texteditingvalue gets displayed on the other page, but my texteditingcontroller do not get recognised in the neugkeitenpage and i cant edit anything there at all.
class InformationContentDetails extends StatefulWidget {
const InformationContentDetails({Key key}) : super(key: key);
#override
State<InformationContentDetails> createState() => _InformationContentDetails();
}
class _InformationContentDetails extends State<InformationContentDetails> {
bool isEnable = false;
var _controller = new TextEditingController(text: 'Allgemeine Informationen');
var _controller2 = TextEditingController();
String name = "Allgemeine Informationen";
String name2 = "Herzlich Willkommen ...";
textlistener(){
print("Update: ${_controller.text}");
print("Update: ${_controller2.text}");
}
#override
void initState() {
super.initState();
// Start listening to changes
_controller.addListener(textlistener);
_controller2.addListener(textlistener);
}
#override
Widget build(BuildContext context) {
return ResponsiveBuilder(
builder: (context, sizingInformation) {
var textAlignment;
if (sizingInformation.deviceScreenType == DeviceScreenType.desktop) {
textAlignment = TextAlign.left;
} else {
textAlignment = TextAlign.center;
}
return Container(
width: 650,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"${_controller.text}",
style: titleTextStyle(sizingInformation.deviceScreenType),
textAlign: textAlignment,
),
TextField(
enabled: true,
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: "Informationen aktualisieren",
),
controller : _controller,
),
FlatButton(
child: Text('bearbeiten'),
onPressed:(){
setState((){
name = _controller.text;
isEnable = !isEnable;
});
},
),
Text(
name2,
style: descriptionTextStyle(sizingInformation.deviceScreenType),
textAlign: textAlignment,
),
Container(
child: TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: "Informationstext aktualisieren"
),
controller : _controller2,
),
),
Container(
child: FlatButton(
child: Text('bearbeiten'),
onPressed:(){
setState((){
name2 = _controller2.text;
isEnable = !isEnable;
});
},
),
),
],
)),
);
},
);
}
#override
void dispose() {
_controller.dispose();
_controller2.dispose();
super.dispose();
}
}
class NeuigkeitenContentDetails extends StatefulWidget {
const NeuigkeitenContentDetails({Key key}) : super(key: key);
#override
State<NeuigkeitenContentDetails> createState() => _NeuigkeitenContentDetailsState();
}
class _NeuigkeitenContentDetailsState extends State<NeuigkeitenContentDetails> {
#override
Widget build(BuildContext context) {
return ResponsiveBuilder(
builder: (context, sizingInformation) {
var textAlignment;
if (sizingInformation.deviceScreenType == DeviceScreenType.desktop) {
textAlignment = TextAlign.left;
} else {
textAlignment = TextAlign.center;
}
return Container(
width: 650,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Neuigkeiten',
style: titleTextStyle(sizingInformation.deviceScreenType),
textAlign: textAlignment,
),
SizedBox(
height: 30,
),
Text(
'Herzlich Willkommen',
style: descriptionTextStyle(sizingInformation.deviceScreenType),
textAlign: textAlignment,
)
],
),
);
},
);
}
}
It isn't clear from your code what you mean by pages.
How does InformationContentDetails relate to, or interact with, NeuigkeitenContentDetails?
If you are using e.g. named routes you may want to look at e.g. Pass arguments to a named route and or Send data to a new screen, if on the other hand you need to send information between different widgets in the widget tree you may need to look at something like Provider - allowing you to read-only or watch for change and rebuild subscribed code, or other state management solutions.
Otherwise, if they exist simultaneously in the widget tree and you don't want to use a dedicated state management solution you need to pass the necessary data up-and-down through parameters which can get messy. H.t.h.
I'm fairly new to Flutter,
I created this script where the Accuracy function adds green TextSpan to the AccuracySpeech list if the spoken word is present in the text string or otherwise it is red.
The script seems to work, the only problem is that I would like once it finishes listening, the Accuracy() function is called and the RichText() appears on the screen (currently the Accuracy() function is called, but the RichText does not appear).
Anyone know how I can fix and make the RichText appear?
import 'dart:core';
import 'package:flutter/material.dart';
import 'package:speech_to_text/speech_recognition_result.dart';
import 'package:speech_to_text/speech_to_text.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
SpeechToText _speechToText = SpeechToText();
bool _speechEnabled = false;
String _lastWords = '';
#override
void initState() {
super.initState();
_initSpeech();
}
/// This has to happen only once per app
void _initSpeech() async {
_speechEnabled = await _speechToText.initialize();
setState(() {});
}
/// Each time to start a speech recognition session
void _startListening() async {
AccuracySpeech.clear();
await _speechToText.listen(onResult: _onSpeechResult);
setState(() {});
}
/// Manually stop the active speech recognition session
/// Note that there are also timeouts that each platform enforces
/// and the SpeechToText plugin supports setting timeouts on the
/// listen method.
void _stopListening() async {
await _speechToText.stop();
Accuracy(_lastWords, text);
setState(() {});
}
/// This is the callback that the SpeechToText plugin calls when
/// the platform returns recognized words.
void _onSpeechResult(SpeechRecognitionResult result) {
setState(() {
_lastWords = result.recognizedWords;
});
}
String text = 'Hi, my name is Gabriele';
List<TextSpan> AccuracySpeech = [];
void Accuracy(String _lastWords, String text) {
var lastWordsSplitted = _lastWords.toLowerCase().split(' ');
var textSplitted = text.toLowerCase().split(' ');
print(lastWordsSplitted);
for (String word in lastWordsSplitted) {
if (textSplitted.contains(word)) {
AccuracySpeech.add(
TextSpan(text: word + ' ', style: TextStyle(color: Colors.green)),
);
} else {
AccuracySpeech.add(
TextSpan(text: word + ' ', style: TextStyle(color: Colors.red)),
);
}
}
print(AccuracySpeech);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Speech Demo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(child: Text(text)),
Container(
padding: EdgeInsets.all(16),
child: Text(
'Recognized words:',
style: TextStyle(fontSize: 20.0),
),
),
Expanded(
child: Container(
padding: EdgeInsets.all(16),
child: Text(
// If listening is active show the recognized words
_speechToText.isListening
? '$_lastWords'
// If listening isn't active but could be tell the user
// how to start it, otherwise indicate that speech
// recognition is not yet ready or not supported on
// the target device
: _speechEnabled
? 'Tap the microphone to start listening...'
: 'Speech not available',
),
),
),
// Todo: Make RichText appear on the screen when stop listening
Expanded(
child: Center(
child: RichText(
text: TextSpan(
style: TextStyle(fontSize: 18.0),
children: AccuracySpeech,
),
),
),
),
/// Listen Button
Center(
child: Container(
child: RawMaterialButton(
onPressed: _speechToText.isNotListening
? _startListening
: _stopListening,
child: Icon(
_speechToText.isNotListening ? Icons.mic_off : Icons.mic,
size: 27,
color: Colors.white,
),
elevation: 0,
shape: CircleBorder(),
constraints: BoxConstraints.tightFor(
width: 48.0,
height: 48.0,
),
),
decoration: BoxDecoration(
color: Color(0xFF25BBC2),
borderRadius: BorderRadius.circular(40.0),
),
),
),
],
),
),
);
}
}
Hope someone can help me.
Thank you :)
I am really struggling to understand why my code isn't working. I'm trying to pass the text from two controllers into another widget with named parameters which writes to Firebase.
My "Test" button properly prints both _titleController.text and _descriptionController.text
TextButton(
onPressed: (){
print(_titleController.text); //works fine
print(_descriptionController.text); //works fine
},
child: Text('test')
),
However when I pass these into my next widget it's blank! If I hardcore strings into these parameters it works properly:
PushNewE3 (
changeTitle: _titleController.text, //does not work (empty)
changeDescription: _descriptionController.text, //does not work (empty)
)
Full code:
class CreateE3 extends StatefulWidget {
const CreateE3({Key? key}) : super(key: key);
#override
_CreateE3State createState() => _CreateE3State();
}
class _CreateE3State extends State<CreateE3> {
final _titleController = TextEditingController();
final _descriptionController = TextEditingController();
#override
void initState(){
super.initState();
_titleController.addListener(_printLatestValue);
}
#override
void dispose(){
_titleController.dispose();
super.dispose();
}
void _printLatestValue(){
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('So Frustrating'),
),
body: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 800,
child: Column(
children: [
Text('Originator: **Add Current User**') ,
TextField(
maxLength: 40,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Change Title'
),
controller: _titleController,
onEditingComplete: (){
//_title = _titleController.text;
},
),
Padding(
padding: const EdgeInsets.fromLTRB(0,10,0,0),
child: TextFormField(
maxLines: 5,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Detailed Description'
),
controller: _descriptionController,
),
),
TextButton(
onPressed: (){
print(_titleController.text); //successfully prints
print(_descriptionController.text); //successfully prints
},
child: Text('test')
),
PushNewE3 (
changeTitle: _titleController.text, //DOES NOT WORK (empty)
changeDescription: _descriptionController.text, //DOES NOT WORK (empty)
)
],
),
),
],
),
);
}
}
class PushNewE3 extends StatelessWidget {
final String changeTitle;
final String changeDescription;
PushNewE3({
required this.changeTitle,
required this.changeDescription
});
#override
Widget build(BuildContext context) {
// Create a CollectionReference called users that references the firestore collection
CollectionReference notificationsE3 = FirebaseFirestore.instance.collection('notificationsE3');
Future<void> pushNewE3() {
// Call the notifications CollectionReference to add a new E3 notification
return notificationsE3
.add({
//'originator': FirebaseAuth.instance.currentUser,
'changeTitle': changeTitle,
'changeDescription': changeDescription,
})
.then((value) => print("E3 Created"))
.catchError((error) => print("Failed to create E3: $error"));
}
return TextButton(
onPressed: (){
print('start:');
print(changeTitle);
print(changeDescription);
print('-end');
},
child: Text(
"Create E3",
),
);
}
}
EDIT:
I still don't understand why the above code doesn't work. I refactored my code into a single widget and now it's working. If anyone can explain why I would still appreciate understanding as there is clearly a gap in my knowledge.
If anyone in the future runs into the same problem here is the refactored code:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'main.dart';
var global = 'blank';
class CreateE3 extends StatefulWidget {
const CreateE3({Key? key}) : super(key: key);
#override
_CreateE3State createState() => _CreateE3State();
}
class _CreateE3State extends State<CreateE3> {
final _titleController = TextEditingController();
final _descriptionController = TextEditingController();
#override
Widget build(BuildContext context) {
// Create a CollectionReference called users that references the firestore collection
CollectionReference notificationsE3 = FirebaseFirestore.instance.collection('notificationsE3');
Future<void> pushNewE3() {
// Call the notifications CollectionReference to add a new E3 notification
return notificationsE3
.add({
//'originator': FirebaseAuth.instance.currentUser,
'changeTitle': _titleController.text,
'changeDescription': _descriptionController.text,
})
.then((value) => print("E3 Created"))
.catchError((error) => print("Failed to create E3: $error"));
}
return Scaffold(
appBar: AppBar(
title: Text(_titleController.text),
),
body: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 800,
child: Column(
children: [
Text('Originator: **Add Current User**') ,
TextField(
maxLength: 40,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Change Title'
),
controller: _titleController,
onChanged: (text){
setState(() {
});
},
),
Padding(
padding: const EdgeInsets.fromLTRB(0,10,0,0),
child: TextFormField(
maxLines: 5,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Detailed Description'
),
controller: _descriptionController,
),
),
TextButton(
onPressed: (){
pushNewE3();
},
child: Text('SAVE')
),
],
),
),
],
),
);
}
}
in the onPressed To pass a value and show it, you have to use setState(() { _myState = newValue; });
Something like this
TextButton(
onPressed: (){
print(_titleController.text);
print(_descriptionController.text);
setState(() { _myNewText = _titleController.text; });
},
child: Text('test')
),
I'm not sure what are you trying to do exactly but here's what I did:
1 - add a local variable _title
2 - add this code to the onPressed function:
setState(() {
_title= _titleController.text;
});
This is the whole code :
class CreateE3 extends StatefulWidget {
const CreateE3({Key? key}) : super(key: key);
#override
_CreateE3State createState() => _CreateE3State();
}
class _CreateE3State extends State<CreateE3> {
final _titleController = TextEditingController();
final _descriptionController = TextEditingController();
String _title = 'So Frustrating';
#override
void initState(){
super.initState();
}
#override
void dispose(){
_titleController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(_title),
),
body: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 400,
child: Column(
children: [
Text('Originator: **Add Current User**') ,
TextField(
maxLength: 40,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Change Title'
),
controller: _titleController,
onEditingComplete: (){
//_title = _titleController.text;
},
),
Padding(
padding: const EdgeInsets.fromLTRB(0,10,0,0),
child: TextFormField(
maxLines: 5,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Detailed Description'
),
controller: _descriptionController,
),
),
TextButton(
onPressed: (){
print(_titleController.text);
print(_descriptionController.text);
setState(() {
_title = _titleController.text;
});
},
child: Text('test')
),
],
),
),
],
),
);
}
}
.........................
so this is when you first start the app :
after changing the TextField and pressing the 'test button the title in the appbar change :
I am trying to build a dynamic Authentication Screen i.e I have a form which shows fields depending on whether the form isLoginForm or not.
I tried initialising the CustomForm class in the State of my LoginScreen but everytime I hot reload or restart, the app says that the column's child is null i.e. the CustomForm is null.
I initialized the form in the void initState() because it also takes textControllers as one of its parameters in the constructor.
Here is the code for LoginScreen class:
class LoginScreen extends StatefulWidget {
LoginScreen({Key key}) : super(key: key);
TextEditingController _nameController;
TextEditingController _emailController;
TextEditingController _passwordController;
CustomForm _form;
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
final _scaffoldKey = GlobalKey<ScaffoldState>();
final _formKey = GlobalKey<FormState>();
#override
void initState() {
widget._nameController = TextEditingController();
widget._emailController = TextEditingController();
widget._passwordController = TextEditingController();
initForm();
widget._nameController.addListener(_nameControllerListener);
widget._emailController.addListener(_emailControllerListener);
widget._passwordController.addListener(_passwordControllerListener);
super.initState();
}
void initForm() {
widget._form = CustomForm(
isLoginForm: false,
nameController: widget._nameController,
passwordController: widget._passwordController,
emailController: widget._emailController,
);
}
#override
void dispose() {
widget._nameController.removeListener(_nameControllerListener);
widget._nameController.dispose();
widget._emailController.removeListener(_emailControllerListener);
widget._emailController.dispose();
widget._passwordController.removeListener(_passwordControllerListener);
widget._passwordController.dispose();
super.dispose();
}
void _nameControllerListener() {
print("(_nameValue Call)__name value is: ${widget._nameController.text}\n");
}
void _emailControllerListener() {
print(
"(_emailValue Call)__email value is: ${widget._emailController.text}\n");
}
void _passwordControllerListener() {
print(
"(_passwordValue Call)__password value is: ${widget._passwordController.text}\n");
}
#override
Widget build(BuildContext context) {
ScreenUtil.init();
return Scaffold(
body: Container(
height: double.infinity,
width: double.infinity,
child: SafeArea(
child: SingleChildScrollView(
child: SizedBox(
height: 1920.h - MediaQuery.of(context).padding.top,
child: Stack(children: <Widget>[
SvgPicture.asset('assets/svg/login/top_left.svg',
width: 320.w),
Positioned(
bottom: 0,
right: 0,
child: SvgPicture.asset(
'assets/svg/login/bottom_right.svg',
width: 320.w)),
Center(
child: Container(
width: 793.w,
child: Column(children: <Widget>[
SizedBox(height: 223.h),
Text('Login',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 100.sp,
fontFamily: 'Avenir')),
SizedBox(height: 60.h),
SvgPicture.asset('assets/svg/login/main_image.svg',
width: 266.w),
SizedBox(height: 143.h),
widget._form,
])),
)
]),
),
),
)));
}
}
And here is the code for the CustomForm class:
class CustomForm extends StatefulWidget {
CustomForm(
{Key key,
this.isLoginForm,
this.nameController,
this.emailController,
this.passwordController})
: super(key: key);
bool isLoginForm;
final nameController;
final emailController;
final passwordController;
#override
_CustomFormState createState() => _CustomFormState();
}
class _CustomFormState extends State<CustomForm> {
CustomTextFormField _name;
CustomTextFormField _email;
CustomTextFormField _password;
final authBloc = AuthBloc();
#override
void initState() {
_name = CustomTextFormField(
hint: "Your Name",
isPassword: false,
isLoginForm: widget.isLoginForm,
keyboardType: TextInputType.emailAddress,
textController: widget.nameController,
stream: authBloc.nameStream,
onChanged: authBloc.nameSink,
);
_email = CustomTextFormField(
hint: "Your Email",
isPassword: false,
isLoginForm: widget.isLoginForm,
keyboardType: TextInputType.emailAddress,
textController: widget.emailController,
stream: authBloc.emailStream,
onChanged: authBloc.emailSink,
);
_password = CustomTextFormField(
hint: "Password",
isPassword: true,
isLoginForm: widget.isLoginForm,
keyboardType: TextInputType.visiblePassword,
textController: widget.passwordController,
stream: authBloc.passwordStream,
onChanged: authBloc.passwordSink,
);
super.initState();
}
#override
Widget build(BuildContext context) {
ScreenUtil.init();
double rectangleGap1h = widget.isLoginForm ? 20.h : 10.h;
double rectangleGap2h = widget.isLoginForm ? 23.h : 14.h;
double btnHeight = widget.isLoginForm ? 133.h : 120.h;
String submitBtnText = widget.isLoginForm ? "Login" : "Sign Up";
String redirectText = widget.isLoginForm ? "Sign Up" : "Login";
String bottomQuestionText = widget.isLoginForm
? "Don\'t have an account?"
: "Already have an account?";
int _defaultRadioVal = -1;
return Form(
child: Column(
children: <Widget>[
Visibility(
visible: !widget.isLoginForm,
child: Column(
children: <Widget>[
//RADIO GROUP
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Radio(
value: 0,
groupValue: _defaultRadioVal,
onChanged: (int i) {}),
Text('Customer'),
Radio(
value: 0,
groupValue: _defaultRadioVal,
onChanged: (int i) {}),
Text('Designer'),
],
),
SizedBox(height: rectangleGap1h),
_name,
SizedBox(height: rectangleGap1h),
],
),
),
_email,
SizedBox(
height: rectangleGap1h,
),
_password,
SizedBox(height: rectangleGap1h),
_buildSubmitButton(submitBtnText, btnHeight),
SizedBox(
height: rectangleGap2h,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
SizedBox(width: 71.w),
Text(
bottomQuestionText,
style: TextStyle(
color: kHintTextColor,
fontSize: 43.sp,
fontFamily: 'Avenir',
),
),
Text(
redirectText,
style: TextStyle(
color: kPrimaryColor,
fontSize: 43.sp,
fontFamily: 'Avenir',
fontWeight: FontWeight.w700,
),
),
SizedBox(width: 71.w),
// Visibility(
// visible: !widget.isLoginForm,
// child: _buildBottomSignUpContainer()),
],
)
],
),
);
}
Every time I rerun the app it seems to work but on hot reload and restart it doesn't work.
Will this work otherwise or will this thing cause an error later as well?
Is this just because on hot reload the initState() method is not called?
Please help
Thank you :)
I am getting the error quoted above when I try to rebuild a class. The class I am calling, ListOfIngs(), is a class that basically creates a textField, but my goal is to create a large amount of TextFields, the variable countIngs holds the value for the exact number, in a listView. Here is the code:
class NewGroceryList extends State<NewGroceryListWidget> {
final GlobalKey<_ListOfIngsState> _key = GlobalKey();
final myController = new TextEditingController();
int countings = 0;
Widget build(BuildContext context) {
debugPrint(myController.text);
return Scaffold(
appBar: AppBar(
title: Text("New Grocery List"),
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios, color: Colors.white),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ListsPage()),
);
},
),
actions: <Widget>[
IconButton(
icon: new Icon(Icons.check, color: Colors.white),
onPressed: () {})
],
),
drawer: AppDrawer(),
body: Container(
padding: EdgeInsets.fromLTRB(10.0, 20.0, 10.0, 30.0),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Text('Ingredients',
style: GoogleFonts.biryani(fontSize: 15.0)),
IconButton(
icon: new Icon(Icons.add),
onPressed: () {
setState(() {
countings++;
});
debugPrint('$countings');
},
)
],
),
setState(() {
ListOfIngsWidget(countings);
}),
],
),
));
}
}
Here is the ListOfIngs class/Widget:
class ListOfIngsWidget extends StatefulWidget {
final int countIngs;
const ListOfIngsWidget(this.countIngs, {Key key}) : super(key: key);
#override
_ListOfIngsState createState() => _ListOfIngsState();
}
class _ListOfIngsState extends State<ListOfIngsWidget> {
List<TextEditingController> _controllerList = [];
List<TextField> _textFieldList = [];
#override
void initState() {
for (int i = 1; i <= widget.countIngs; i++) {
TextEditingController controller = TextEditingController();
TextField textField = TextField(
controller: controller,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Ingredient $i',
),
);
_textFieldList.add(textField);
_controllerList.add(controller);
}
super.initState();
}
#override
Widget build(BuildContext context) {
return new Container(
child: Flexible(
child: ListView(children: _textFieldList),
),
);
}
}
Remove the setState around the ListOfIngsWidget and add a UniqueKey() to it like so:
ListOfIngsWidget(countings, key: UniqueKey()).