Flutter get class field value back and forth - flutter

I'm trying to create a custom checkbox widget and I'm having trouble getting the bool value of that checkbox from another class:
So am having a form in stateful widget Signup, within this form I'm calling my CustomCheckBox widget (also a stateful widget).
The issue: When I click on the checkbox its value change to true in the CustomCheckBox widget however after submitting the form in Signup widget the value always false (seams to be no back communication between the the two widgets)
My CustomCheckBox code:
import 'package:flutter/material.dart';
import 'package:tunimmo/Constants/palette.dart';
class CustomCheckBox extends StatefulWidget {
bool checked;
final String label;
CustomCheckBox({this.checked, this.label});
#override
_CustomCheckBoxState createState() => _CustomCheckBoxState();
}
class _CustomCheckBoxState extends State<CustomCheckBox> {
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(top: 15.0, left: 30, right: 30),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Container(
height: 30,
decoration: BoxDecoration(
color: myPrimaryColor,
),
child: Text(" "),
),
Text(' ${widget.label}', style: Theme.of(context).textTheme.bodyText1),
],
),
Center(
child: InkWell(
onTap: () {
setState(() {
widget.checked = !widget.checked;
});
},
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: widget.checked ? myPrimaryColor : myWhiteColor,
border: Border.all(
color: myPrimaryColor,
width: 3,
),
),
child: Padding(
padding: const EdgeInsets.all(3.0),
child: widget.checked
? Icon(
Icons.check,
size: 25.0,
color: myWhiteColor,
)
: Icon(
Icons.check_box_outline_blank,
size: 25.0,
color: myWhiteColor,
),
),
),
)),
],
),
);
}
}
In the Signup widget I'm just calling the constructor and passing a bool field (expected to send/get the value in the CustomCheckBox widget) and a string label.
PS: I have more than one checkbox in my form.
Please advice!

The problem is that you are not changing the checked value in the screen(signup) but changing in the custom checkbox, to solve this issue define checked variable in SignUp if not already did, then define Function call back in the checkbox widget as follows:
final Function(bool)checkChanged;
CustomCheckBox({this.checked, this.label,this.checkedChanged});
then call it in ontap and give the value change
onTap: () {
widget.checkedChanged(!widget.checked);
setState(() {
widget.checked = !widget.checked;
});
}
do the following when calling the CustomCheckbox:
CustomCheckBox(
checked:false,
label:'a label',
checkedChanged:(val){
checked=val;
}
)
and use that checked variable when submitting the form and that should solve your problem.

Related

Flutter - How to select an item (tag) automatically in the UI - List<dynamic>

I am trying to preselect a particular tag shown on the right of the image.
However, I am unable to figure out where to set it. The tags are coming from an API (Postgres backend).
Once it is built to a list of overlay as shown on the right again in the screenshot. I just wanted it to preselect, "Morning", "Evening" or "Daytime" based on the time of the day.
To start off with, I am not able to preselect anything in "selectedTags". This can only be done manually by the user when clicked on a tag.
The method is shared below.
showTagPicker(context, allTags) async {
await showModalBottomSheet(
isDismissible: false,
enableDrag: false,
backgroundColor: Colors.transparent,
isScrollControlled: true,
context: context,
builder: (builder) => Center(
child: Container(
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(10),
),
color: Colors.white,
),
margin: EdgeInsets.all(16),
padding: EdgeInsets.all(24),
child: ListView(
shrinkWrap: true,
children: <Widget>[
Text(
"Please pick your tags",
style: TextStyle(fontSize: 16),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: TagPicker(
height: MediaQuery.of(context).size.height * .6,
tags: allTags,
onTagSelected: (_selectedTags) {
selectedTags = _selectedTags;
print("----->");
print(selectedTags);
print("<-----");
},
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
RaisedButton(
color: PRIMARY,
textColor: WHITE,
onPressed: () {
Navigator.of(context).pop();
navigateToAnalysis(context);
},
child: Text("Save"),
),
],
)
],
),
),
),
);
}
I tried, adding "print" to debug and see what and where things are being set but I did not get any further, I have also shown the debug screen if it helps.
Any direction here to preselect one/many tags would be helpful.
Please let me know if I must provide additional details to solve this.
Also, I know there are several things in the code which might be wrong, it is inherited code and I am struggling a bit.
Edit: Including TagPicker. It is not a public library but our widget.
class TagPicker extends StatefulWidget {
const TagPicker(
{Key key, this.height, this.tags, this.onTagSelected, this.selectedTags})
: super(key: key);
#override
TagPickerState createState() => TagPickerState();
final double height;
final List tags;
final List selectedTags;
final Function onTagSelected;
}
class TagPickerState extends State<TagPicker> {
List selectedTags = [];
#override
void initState() {
super.initState();
if (widget.selectedTags != null) {
setState(() {
selectedTags = widget.selectedTags;
});
}
}
#override
Widget build(BuildContext context) {
return widget.tags != null
? Container(
constraints: widget.height != null
? BoxConstraints(maxHeight: widget.height, minHeight: 60)
: BoxConstraints(),
child: SingleChildScrollView(
child: Wrap(
spacing: 0.0,
children: List.generate(
widget.tags.length,
(index) {
return Padding(
padding: const EdgeInsets.only(right: 4.0),
child: ChoiceChip(
selectedColor: PRIMARY,
labelStyle: TextStyle(
fontSize: 12,
color: selectedTags.contains(widget.tags[index])
? WHITE
: Colors.black),
label: Text(widget.tags[index]['tag_name']),
selected: selectedTags.contains(widget.tags[index]),
onSelected: (selected) {
setState(() {
selectedTags.contains(widget.tags[index])
? selectedTags.remove(widget.tags[index])
: selectedTags.add(widget.tags[index]);
widget.onTagSelected(selectedTags);
});
},
),
);
},
),
),
),
)
: Container();
}
}
Pass selectedTags as an argument to TagPicker and modify TagPicker to render an initial set of selected tags. As before onTagSelected callback will provide an updated set.

How to pass user's TextFormField input to a button in a different class in flutter

I am creating a flutter app. For the code reusability, I need to differentiate Email and password forms and Login Button, I am not sure how to properly to pass the input from textformfield to the button for the form to be validated, when clicking it. Here's my code. Note that im a beginner in flutter.
//This is my EmailTextForm class:
class EmailTextForm extends StatelessWidget {
String email;
EmailTextForm({Key key, this.email}) : super(key: key);
Widget build(BuildContext context) {
return Container(
width: 370.0,
height: 54.0,
child: TextFormField(
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
//DEFAULT STATE OF THE BORDER(FOCUSED BORDER DOWN BELOW TO HAVE MORE CONTROL OF THE FORM)
borderSide: BorderSide(
width: 1.0, color: Color.fromRGBO(16, 25, 53, 0.1)),
borderRadius: BorderRadius.circular(12.0)),
focusedBorder: OutlineInputBorder(
//ON FOCUSED BORDER TO NOT CHANGE STATE WHILE BEING PRESSED ON
borderSide: BorderSide(
width: 1.0, color: Color.fromRGBO(16, 25, 53, 0.1)),
borderRadius: BorderRadius.circular(12.0),
),
prefixIcon: Icon(Icons.mail, color: Color(0xFF9FA3AE)),
hintText: 'El.Paštas',
hintStyle: TextStyle(
fontFamily: 'Sora',
fontSize: 16.0,
color: Color(0xFF9FA3AE),
),
),
validator: (input) =>
!input.contains('#') ? 'Please enter a valid email' : null,
onSaved: (input) => email = input,
));
}
}
//This is the button class.
import 'package:flutter/material.dart';
import 'dart:math' as math;
class LoginButton extends StatelessWidget {
final _formKey = GlobalKey<FormState>();
String email;
String password;
_submit() {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
print('validated');
//logging in the user
}
}
#override
Widget build(BuildContext context) {
//Container to manipulate button design
return Container(
width: 370.0,
height: 54.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular((12.0)),
gradient: LinearGradient(
//change gradient, wrong value, maybe something in AdobeXD.
colors: <Color>[Color(0xFF00BAFF), Color(0xFF448CFA)],
stops: [0.0, 1.0],
begin: Alignment(-1.0, 0.0),
end: Alignment(1.0, 0.0),
transform: GradientRotation(math.pi / 2),
),
boxShadow: [
BoxShadow(
color: Color.fromRGBO(48, 183, 241, 1.0),
offset: Offset(0.0, 4.0),
blurRadius: 12.0,
),
],
),
//#### WHEN BUTTON IS PRESSED ####
child: ElevatedButton(
onPressed: _submit,
child: Text(
'Prisijungti',
),
style: ElevatedButton.styleFrom(
//COLOR OF THE TEXT INSIDE THE BUTTON
onPrimary: Color(0xFFFFFFFF),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0),
),
primary: Colors.transparent,
textStyle: TextStyle(
//Text inside button style
fontSize: 16.0,
fontWeight: FontWeight.w600,
fontFamily: 'Sora',
)),
));
}
}
Accessing Field Data
The code sample at bottom shows two different ways to get access to the email field value using:
FormFieldState
TextEditingController
These two methods don't rely on having a Form wrapping your fields (although it's often convenient to do so, giving you more options for handling form data & showing validation errors.)
Why use Form?
A Form widget wrapping fields is useful for handling/manipulating several fields together as a group for things such as form resetting, validation, and submitting.
We access these Form functions via a GlobalKey<FormState> that we give to the Form when we declare it.
child: Form(
key: formKey, // declared above as a field in our State object
For example, TextFormField has a validator: argument (takes a function). If our field is inside a Form, we can ask the Form call all validator functions to "validate" our form:
formKey.currentState.validate();
The validator: will display any non-null String you return to it:
Code Sample
import 'package:flutter/material.dart';
class FormValuesPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Form Values'),
),
body: FormValuesExample(),
);
}
}
class FormValuesExample extends StatefulWidget {
#override
_FormValuesExampleState createState() => _FormValuesExampleState();
}
class _FormValuesExampleState extends State<FormValuesExample> {
GlobalKey<FormState> formKey = GlobalKey<FormState>();
GlobalKey<FormFieldState> emailFieldKey = GlobalKey();
TextEditingController emailController = TextEditingController();
#override
void dispose() {
emailController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 20),
child: Form(
key: formKey, // declared above as a field in our State object
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
TextFormField(
key: emailFieldKey,
controller: emailController,
decoration: InputDecoration(
labelText: 'Email'
),
validator: (val) => validateEmail(val),
),
LoginButton(formKey: formKey, fieldKey: emailFieldKey, controller: emailController,)
],
),
),
);
}
String validateEmail(String email) {
if (email == null || email.isEmpty)
return 'Email cannot be empty';
return null;
}
}
class LoginButton extends StatelessWidget {
final GlobalKey<FormState> formKey;
final GlobalKey<FormFieldState> fieldKey;
final TextEditingController controller;
LoginButton({this.formKey, this.fieldKey, this.controller});
#override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
formKey.currentState.validate();
print('from FormFieldState ${fieldKey.currentState.value}');
print('from controller: ${controller.text}');
},
child: Text('Submit'));
}
}
You need to wrap them in a Form widget and pass the key, for example:
Form(
key: _keyForm
child: Column(
children: <Widget>[
EmailTextFieldForm(),
PasswordTextFieldForm(),
FormButton(),
],
)
)
you need to wrap all the TextFormFields in a form to get it like this
Column(
children: [
TextFormField(),
....
TextFormField(),
])
TextFormFields can be wrapped or moved to another widget, as long as it is a child of the Form.
if everything is in one widget
Form(
child:
Column(
children: [
TextFormField(),
....
TextFormField(),
Button(
onTap: () {},
),
])
you need to wrap the button in the Builder so that the context of the current element in the tree is available
Builder(
builder: (context) => Button(
onTap: () {},
),
),
and after that, you can do Form.of(context).validate(). This entry will find the first form higher in the tree and validate all text fields.
in this way you should get out like this
Builder(
builder: (context) => Button(
onTap: () {
Form.of(context).validate()
},
),
)
if the button is placed in a separate widget, then there is no need to wrap it in the Builder, you can simply call the validation, since the context below the form is available to you
Button(
onTap: () {
Form.of(context).validate()
},
),
also, you can create GlobalKey
and use validation with a key. You can pass key, for example, through the constructor(if needed)
final _formKey = GlobalKey<FormState>();
Form(
key: _formKey
child: Column(
children: [
TextFormField(),
....
Button(
onTap: () {
_formKey.currentState!.validate ()
}
)
],
),
)

DragTarget doesnt call onWillAccept with custom Draggable (Flutter)

I am trying to make Tags which are draggable text so that I can drag them to one of 2 DragTarget I have (ideally being able to move them between 3 DragTarget). Unfortunately I can't make them interact with the DragTargets as they dont even call onWillAccept(). My draggables are DragabbleTag and extends Draggable and my dragTargets are in a Stateful Widget and should accept them.
import 'package:myApp/components/draggableTag.dart';
import 'package:flutter/material.dart';
class DraggableTagTarget extends StatefulWidget {
final String title;
final int maxTagAmount;
final Color backgroundColor;
final List<DraggableTag> tagsPool;
const DraggableTagTarget(
{Key key,
this.title,
this.backgroundColor,
this.tagsPool,
this.maxTagAmount})
: super(key: key);
#override
_DraggableTagTargetState createState() => _DraggableTagTargetState();
}
class _DraggableTagTargetState extends State<DraggableTagTarget> {
String test = "Test";
#override
Widget build(BuildContext context) {
return DragTarget<DraggableTag>(onAccept: (DraggableTag value) {
setState(() {
widget.tagsPool.add(value);
test = value.label;
});
}, onWillAccept: (DraggableTag data) {
bool result =
widget.tagsPool.length <= widget.maxTagAmount ? true : false;
debugPrint("ONWillAccept: " + data.label + " = " + result.toString());
return result;
}, builder: (context, candidateData, rejectedData) {
return Container(
decoration: new BoxDecoration(
color: widget.backgroundColor,
border: Border.all(
color: Colors.black,
),
),
child: Column(
children: <Widget>[
Text(test),
Text(widget.title),
SizedBox(
height: 60,
child: Wrap(
children: widget.tagsPool,
),
),
],
),
);
});
}
}
Custom DragTarget 'DraggableTagTarget'
import 'package:flutter/material.dart';
class DraggableTag extends Draggable<String> {
final String label;
DraggableTag({Key key, this.label})
: super(
key: key,
data: label,
child: idleTag(label),
feedback: feedbackTag(label),
childWhenDragging: ghostTag(label),
);
static Widget idleTag(String label) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 2.0),
child: Text(
label,
style: TextStyle(
fontSize: 16,
),
),
decoration: BoxDecoration(
color: Colors.blue,
border: Border.all(
color: Colors.black,
),
borderRadius: BorderRadius.all(Radius.circular(20)),
),
);
}
Custom Draggable 'DraggableTag'
I excluded feedbackTag() and ghostTag which shouldnt be relevant
At first my draggableTag was extending a widget but seeing some similar problem I made it into extending directly a Draggable but it didnt help
EDIT:
I am assigning ma values to draggable in a custom DialogWidget (stateful widget) in a list
class _RatingDialogState extends State<RatingDialog> {
List<DraggableTag> tagsPool = [
DraggableTag(label: "Acting"),
DraggableTag(label: "Scenario"),
DraggableTag(label: "Pace"),
DraggableTag(label: "Length"),
DraggableTag(label: "Message"),
];
List<DraggableTag> negativeTagsPool = [];
List<DraggableTag> positiveTagsPool = [];
#override
Widget build(BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
elevation: 0,
backgroundColor: Colors.transparent,
child: contentBox(context),
);
}
contentBox(context) {
return Stack(
...
Wrap(
children: tagsPool,
),
SizedBox(height: 22),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Flexible(
child: FractionallySizedBox(
widthFactor: 0.85,
child: DraggableTagTarget(
title: "Negative",
backgroundColor: Colors.red,
tagsPool: negativeTagsPool,
maxTagAmount: 3),
),
),
Flexible(
child: FractionallySizedBox(
widthFactor: 0.85,
child: DraggableTagTarget(
title: "Positive",
backgroundColor: Colors.green,
tagsPool: positiveTagsPool,
maxTagAmount: 3),
),
),
]),
...
SOLUTION: as ikerfah explained, I didnt put the right type into <> because I was confused to what my DraggableTag class was. I made another class to contains the data Tag so that both my DragTarget and DraggableTag use this class
Draggable and DragTarget must have the same generic type, but you have Draggable<String> and DragTarget<DraggableTag>

textfield focus triggers rebuilding of UI

when I set Textfield autofocus:false it doesn't refresh the page but when I tap on the TextField, the keyboard shows then the main page rebuilds which causes lag.
This has been a problem for almost a week now. I can find problems related to textfields rebuilding UI but the solution cannot be applied to mine.
MAIN PAGE CONTAINS THIS FUNCTION WHEN A BUTTON IS CLICKED
void addCommentModal() {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Container(
padding:
EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: AddCommentModal(
onPost: (String text) {
// APIServices.commentPost(context, i.toString(), text);
Navigator.pop(context);
},
),
);
},
);
}
AddCommentModal
class AddCommentModal extends StatefulWidget {
final ValueChanged<String> onPost;
AddCommentModal({#required this.onPost});
#override
_AddCommentModalState createState() => _AddCommentModalState();
}
class _AddCommentModalState extends State<AddCommentModal> {
final commentController = TextEditingController();
bool _canPost = false;
String defaultProfilePhoto = "";
#override
void initState() {
defaultProfilePhoto = Constants.userFirstName[0].toUpperCase();
super.initState();
}
#override
void dispose() {
commentController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
print("PHOTO: ${Constants.userProfilePhoto}");
return Container(
padding: EdgeInsets.all(10),
child: Row(
children: <Widget>[
Container(
width: 50,
height: 50,
child: ClipRRect(
borderRadius: new BorderRadius.circular(50),
child: Constants.userProfilePhoto == null
? Container(
color: Color(colorPrimary),
alignment: Alignment.center,
child: Text(
defaultProfilePhoto,
style: TextStyle(
color: Color(colorText), fontSize: 20),
),
)
: Image.network(
APIServices.httpDomain + Constants.userProfilePhoto,
fit: BoxFit.cover,
)),
),
Expanded(
child: Container(
margin: EdgeInsets.only(
left: 10,
),
child: TextField(
controller: commentController,
autofocus: true,
decoration: new InputDecoration(
suffixIcon: IconButton(
onPressed: () => widget.onPost(commentController.text),
icon: Icon(
FontAwesomeIcons.paperPlane,
size: 15,
color: Theme.of(context).primaryColor,
)),
contentPadding: EdgeInsets.all(10),
hintText: "Add a comment ...",
fillColor: Colors.white,
border: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(20.0),
),
),
keyboardType: TextInputType.text,
style: new TextStyle(fontFamily: "Poppins", fontSize: 15),
),
))
],
));
}
}
Faced the same issue, been trying for hours :
if your screen depends on MediaQuery or at least having one widget
depenig on MediaQuery, the keyboard popup changes the size of your
screen, which triggers mediaQuery and causing rebuilds...in this case
avoid using mediaQuery, Instead get your dimensions using (sizer
package) https://pub.dev/packages/sizer
Replaced everything related to mediaQuery and now works fine.
It was caused by an unoptimized code on Flutter's SDK: https://github.com/flutter/flutter/issues/37878.
The fix was merged very recently and is on the "master" channel.
Consider switching to that channel, using flutter channel master.

flutter radiovalue not changing

I'm trying to get a very simple set of radiobuttons up, which is why it's so frustrating that they aren't working. I've tried setting this up in a similar class, and it's worked. I know for a fact that setstate is being called, but for some reason it's not updating the individual radio button. Which makes me think that this is some weird issue related to state.
Anyways, all help would be appreciated. My main class is the second part of the code below.
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../bloc/thembloc.dart';
import './components/textfield.dart';
class SignUp extends StatefulWidget {
#override
_SignUpState createState() => _SignUpState();
}
class _SignUpState extends State<SignUp> {
/*
ui for signup
includes multiple textfields.
includes all of the information that we'll need
to collect for an user to register an account.
todo: wrap everything in a form, encrypt it and send it to a private server.
*/
#override
Widget build(BuildContext context) {
double _height = MediaQuery.of(context).size.height;
double _width = MediaQuery.of(context).size.width;
final double _margin = 16.0;
final double _promptWidth = _width - 32.0;
final double _promptHeight = _height - 32.0;
final double _textFieldWidth = _promptWidth - 32.0;
int subscriberValue;
void switchSubscriber(int value) {
setState(() {
subscriberValue = value;
});
}
return BlocBuilder(
bloc: BlocProvider.of<ThemeBloc>(context),
builder: (context, ThemeState state) {
return Scaffold(
resizeToAvoidBottomInset: false,
resizeToAvoidBottomPadding: false,
appBar: AppBar(
centerTitle: true,
title: Text(
"smartmoney",
style: BlocProvider.of<ThemeBloc>(context).currentState.themedata.primaryTextTheme.display2,
),
// appbar
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(8.0),
bottomRight: Radius.circular(8.0))),
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: BlocProvider.of<ThemeBloc>(context).currentState.themedata.buttonColor,
),
onPressed: () {
print("going back");
},
),
backgroundColor: BlocProvider.of<ThemeBloc>(context).currentState.themedata.canvasColor,
),
body: Container(
height: _height,
width: _width,
color: BlocProvider.of<ThemeBloc>(context).currentState.themedata.backgroundColor,
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: _margin),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(8.0)),
color: BlocProvider.of<ThemeBloc>(context).currentState.themedata.canvasColor,
boxShadow: [
BoxShadow(
spreadRadius: 0.0,
color: Colors.black38,
blurRadius: 6.0,
offset: Offset(0.0, 3.0)),
]),
width: _promptWidth,
height: _promptHeight - 48 - _margin,
child: Column(
children: <Widget>[
Text("Let's get started",
style: BlocProvider.of<ThemeBloc>(context).currentState.themedata.primaryTextTheme.display2,
),
Text("Enter your information to create an account",
style: BlocProvider.of<ThemeBloc>(context).currentState.themedata.primaryTextTheme.subtitle,
),
Padding(
padding: EdgeInsets.only(top: 8.0),
child: StyledTextField(
textFieldWidth: _textFieldWidth,
helperText: "First name",
),
),
Padding(
padding: EdgeInsets.only(top: 8.0),
child: StyledTextField(
textFieldWidth: _textFieldWidth,
helperText: "Last name",
),
),
Padding(
padding: EdgeInsets.only(top: 8.0),
child: StyledTextField(
textFieldWidth: _textFieldWidth,
helperText: "Email",
),
),
Padding(
padding: EdgeInsets.only(top: 8.0),
child: StyledTextField(
textFieldWidth: _textFieldWidth,
helperText: "Password",
),
),
Padding(
padding: EdgeInsets.only(top: 8.0),
child: StyledTextField(
textFieldWidth: _textFieldWidth,
helperText: "Phone number",
),
),
Text("Subscriber type",
style: BlocProvider.of<ThemeBloc>(context).currentState.themedata.primaryTextTheme.display1,
),
Radio(
groupValue: subscriberValue,
value: 0,
onChanged: (int value) => switchSubscriber(value),
),
Radio(
groupValue: subscriberValue,
value: 1,
onChanged: (int value) => switchSubscriber(value),
)
],
),
),
)
],
),
),
);
});
}
}
import 'package:flutter/material.dart';
import './bloc/thembloc.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'ui/signin.dart';
import 'ui/signup.dart';
import 'ui/onboarding.dart';
import './ui/testing/whatthefuck.dart';
void main() {
runApp(
MaterialApp(
home: SmartMoney(),
)
// SmartMoney()
);
}
class SmartMoney extends StatefulWidget {
#override
_SmartMoneyState createState() => _SmartMoneyState();
}
class _SmartMoneyState extends State<SmartMoney> {
final _themeBloc = ThemeBloc();
#override
Widget build(BuildContext context) {
return BlocProvider(
bloc: _themeBloc,
child: SignUp(),
);
}
}
The problem is because you defined your variable subscriberValue inside your build method. You're using setState calls that recall build method and in every recall of build you're losing the value of subscriberValue. I advise you to always use variables that will control the state of your widget as class members.
class _SignUpState extends State<SignUp> {
// HAS TO BE CLASS MEMBER AND IT'S GOOD AN INITIAL VALUE TOO..
int subscriberValue =1; // asuming that 1 is default radio button option
#override
Widget build(BuildContext context) {
//... some codes ...
//int subscriberValue; REMOVE THIS LINE. YOU'RE LOSING THE VALUE IN EVERY setState call
//You can define this method outside from build too.
void switchSubscriber(int value) {
setState(() {
subscriberValue = value;
});
}
}