Redraw all container if are created with method [DART] - flutter

I write my first app, i created three container with method, but if the method setState() in a container it's call the setState do not redraw other containers.
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
children: <Widget>[
//ELEMENT A
elementGS(size, value_A.text, Colors.cyan[600], GSConst.sizeA, 2),
//ELEMENT B
elementGS(size, value_B.text, Colors.blue, GSConst.sizeB, 1),
],
),
//ELEMENT C
elementGS(size, value_AB.text, Colors.red, 1, 3),
],
),
Method for draw a container
Container elementGS(
Size size, String textHint, Color color, double ratioWidth, int flagGS) {
return Container(
alignment: Alignment.center,
padding: EdgeInsets.symmetric(horizontal: GSConst.kDefaultPadding),
height: size.height * GSConst.kHeightElementRatio,
width: sizeInternalBody.width * ratioWidth,
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.all(Radius.circular(30)),
),
child: TextField(
decoration: InputDecoration(
hintText: textHint,
hintStyle: TextStyle(
color: Colors.white,
fontFamily: 'ChristopherDone',
fontSize: 30,
),
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
alignLabelWithHint: true,
),
style: TextStyle(
color: Colors.white,
fontFamily: 'ChristopherDone',
fontSize: 30,
),
textAlign: TextAlign.center,
autocorrect: false,
showCursor: true,
onChanged: (String value) {
setState(() {
if (value.isNotEmpty) {
Map<String, TextEditingController> contr = {
"A": value_A,
"B": value_B,
"AB": value_AB,
};
switch (flagGS) {
case 1:
//In calculateGS calculate the golden ratio and set value in the textcontroller.
contr = calculateGS(contr, b: double.parse(value));
break;
case 2:
contr = calculateGS(contr, a: double.parse(value));
break;
case 3:
contr = calculateGS(contr, ab: double.parse(value));
break;
}
}
});
},
keyboardType: TextInputType.number,
),
);
if I call setState in "element C" I also want redraw "element A" and "element B".
It's possible?
Here you will find all the code
GITHUB GOLDEN RATIO

if I call setState in "element C" I also want redraw "element A" and "element B". It's possible?
Sure! That what youre doing is just not really that what you are expecting because every widget you create, has just its own state which gets updated.
If you want to observe states in other widgets too, you should read (or watch, or learn) a little bit about the BLoC Pattern(Link: https://bloclibrary.dev/#/ ), or in your case, bc its not very big, Provider (https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple ) both are recommended from the flutter team, so choose one what fits your knowlegde and your requirements.

Related

When tap on textfield, app crashes returns homepage

Hi I get an error when user focus textfield, app crashes and returns to homepage (see clip here https://www.screencast.com/t/yiJkCBsibcoY)
I've had this error for a while now and cannot seem to fix it, sometimes it happens on other textfields. I cannot replicate the issue only sent from users. Anyone experience this with flutter?
Widget searchBox() {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25.0),
border: Border.all(color: Color(0xff0F004E), width: 1.0),
),
child: SimpleAutoCompleteTextField(
key: keyAuto,
controller: textController,
suggestions: suggestions,
textChanged: (text) => searchProduct = text,
textSubmitted: (text) {
loadingBarActive = true;
_sendAnalyticsEvent(text, 'serach_food_action');
searchProduct = text.replaceAll(new RegExp(r'[^\w\s]+'), '');
print('searchProduct RegX $searchProduct');
newSearch = true;
_filterCategories(searchProduct);
_filterRecipes(searchProduct);
// reset search values to intial
usdaItems.clear();
usda!.clear();
perPage = perPageIntial;
present.value = 0;
loadingBarActive = false;
selectApi = <int, Widget>{
0: allProductTab(),
1: allProductTab(),
2: allProductTab(),
3: allProductTab(),
};
setState(() {
_loadUSDAlist = usdaFoodProductList();
_loadOpenList = openFoodProductList();
});
},
style: TextStyle(
fontFamily: 'Nunito', fontSize: 20.0, color: Color(0xff0F004E)),
decoration: InputDecoration(
border: InputBorder.none,
// contentPadding: EdgeInsets.only(top: 14.0),
hintText: 'Search',
hintStyle: TextStyle(
fontFamily: 'Nunito', fontSize: 16.0, color: Color(0xff0F004E)),
prefixIcon: Icon(Icons.search, color: Color(0xff0F004E)),
suffixIcon: IconButton(
icon: Icon(Icons.close, color: Color(0xff0F004E)),
onPressed: () {
textController.clear();
})),
),
);
}
I had exactly the same issue and was literally going crazy trying to find the solution. For me the error originated in my usage of the GetX state management library. For me the issue was solved by replacing this:
Get.to(ReservationDetails(res: Reservation.empty()))
?.then(((value) => setState(() {
//Reload the reservations for the new date from the server
_taskesFuture =
FetchReservation(setStatePublic: _setStatePublic)
.fetchReservation(_selectedDate);
})));
with:
Navigator.push(context,
MaterialPageRoute(
builder: ((context) =>
ReservationDetails(res: Reservation.empty()))))
.then((value) => setState(() {
//Reload the reservations for the new date from the server
_taskesFuture =
FetchReservation(setStatePublic: _setStatePublic)
.fetchReservation(_selectedDate);
}));
I suggest you have a look at how you are opening the page you are experiencing this issue.

How to add cursor For PinFieldAutoFill flutter

There is no cursor while entering OTP, How can add Cursor in pinFieldAutoFill. I am using the sms_autofill: ^1.2.5 package.
PinFieldAutoFill(
autofocus: true,
keyboardType: TextInputType.number,
decoration: UnderlineDecoration(
textStyle: TextStyle(
fontSize: 44.sp,
fontWeight: FontWeight.bold,
color: kDarkBlue),
colorBuilder: FixedColorBuilder(
Colors.grey),
),
currentCode: authService
.loginMobileOTP, // prefill with a code
onCodeSubmitted: (_) async {
authService.login(
context, _scaffoldKey);
},
onCodeChanged: (value) {
authService.loginMobileOTP =
value;
},
codeLength:
6 //code length, default 6
),
Please enable cursor option in "sms_autofill" package, class constructer "PinInputTextField".
Sharing reference code
return PinInputTextField(
pinLength: widget.codeLength,
decoration: widget.decoration,
cursor: Cursor(
width: 2,
height: 40,
color: Colors.red,
radius: Radius.circular(1),
enabled: true,
),

New Textfield created appear with previous textfield's value in flutter

I have this Widget to register. Inside I want to ask for 6 inputs to register, but as not too much space on the screen, I splitted in 2 pair of 3. I show three at first in a form and when the user press the continue button I show the other 3. However, when I press the continue button, the new 3 pair of TextField appear with the same value of the previous ones. And they move position a little under. I don't know why it happens since each of those 6 fields is different Widget function.
I created two variables form1 and form2 to hold the different forms
#override
void initState() {
super.initState();
form1 = <Widget>[
firstForm(),
Text("Or Sign Up with social media"),
SizedBox(
height: 20,
),
socialMediaButtons(),
SizedBox(
height: 50,
),
Text("Have an account? Login")
];
form2 = <Widget>[
secondForm(),
Text("Or Sign Up with social media"),
SizedBox(
height: 20,
),
socialMediaButtons(),
SizedBox(
height: 50,
),
Text("Have an account? Login")
];
}
All the text field have the same format as the text field below, I only changed the variable for their respecting field.
Widget firstNameField() {
return TextFormField(
initialValue: "",
decoration: InputDecoration(
contentPadding: EdgeInsets.only(top: 10, left: 20, right: 20),
border: InputBorder.none,
hintText: "First Name",
hintStyle: TextStyle(color: Colors.grey[400], fontSize: 15)),
onChanged: (val) {
setState(() => firstName = val);
},
);
}
I combined the text fields in two widgets (firstForm and secondForm). (Shown firstForm but it is the same format as second, just called the functions for the other widgets).
Widget firstForm() {
return Column(
children: <Widget>[
emailPassField(),
SizedBox(
height: 50,
),
continueButton(),
SizedBox(
height: 50,
),
],
);
}
Then this is the continue button widget which when pressed. show the second form. I change the step variable to 2 to go to the second form.
Widget continueButton() {
return ButtonTheme(
minWidth: 185.0,
height: 48.0,
child: RaisedButton(
color: Colors.black,
textColor: Colors.white,
child: Text("continue"),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(50.0)),
onPressed: () => setState(() => step = 2),
));
}
When the variable step is changed, I created this function (getForm) to be called and to show the correct form array variable for the children of the column.
#override
Widget build(BuildContext context) {
return Material(
child: Expanded(
child: Stack(
children: <Widget>[
// banner with picture
Positioned(
child: banner(),
),
// Login Elements Container
Positioned(
child: Container(
margin: EdgeInsets.only(top: 300.0),
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.2),
spreadRadius: 5,
blurRadius: 20,
offset: Offset(0, 0))
],
borderRadius: BorderRadius.only(
topRight: Radius.circular(50),
topLeft: Radius.circular(50))),
child: Center(
child: Column(
children: getForm(step),
),
),
),
)
],
),
),
);
}
//functions for switching forms
getForm(int form) {
if (form == 1) {
return form1;
} else if (form == 2) {
return form2;
}
}
This is how the first step of the form appear.
first form
If I don't enter any data in the text fields and press the continue button, the second form with the correct text fields will appear as shown in this below image. You can see that they have the correct hint text.
second form
However if I enter some data on the first step of the form (seen in second form with data step 1), and then press the continue button, in the second step, the text fields will move down a little bit and the same value entered in the previous text fields will appear in the others too(second form with data step 2). can someone help me please, I don't what's going on there? I hope you understand the code and be able to help me please.
second form with data step 1
second form with data step 2
You need to create a TextEditingController for each TextFormField.
final _emailController = TextEditingController();
final _passwordController = TextEditingController();
...
final _cityController = TextEditingController();
...
// initState
...
// dispose of all TextEditingControllers
#override
void dispose {
_emailController.dispose();
...
_cityController.dispose();
super.dispose();
}
// do this for every TextFormField
Widget firstNameField() {
return TextFormField(
// pass the corresponding controller, no need to set initial value if empty
controller: _firstNameController,
decoration: InputDecoration(
contentPadding: EdgeInsets.only(top: 10, left: 20, right: 20),
border: InputBorder.none,
hintText: "First Name",
hintStyle: TextStyle(color: Colors.grey[400], fontSize: 15)),
onChanged: (val) {
setState(() => firstName = val);
},
);
}
Use a unique TextEditingcontroller for each textfield...by this way the values won't overlap each others textfield value.

Resetting TextfieldController for all textfields, using provider

I'm having a problem trying to figuring out the proper way on how to do this. Basically in my app, I want to reset all the fields for "cleanup" by the user. I can reset everything, but the TextFields. The only way that I found to solve the problem is by using the if that you can see inside the Consumer. I don't think though it's the proper way on how to handle this type of thing.
I also thought to push inside my provider class all the controller and then reset them, but I think it's still too heavy. I'm trying to find the cleanest and lightest solution, even to learn what's the best practice in these situations.
Thanks in advance!
return Provider.of<Provider_Class>(context, listen: false).fields[_label] != null ? SizedBox(
height: 57.5,
child: Consumer<Provider_Class>(builder: (context, provider, child) {
if (provider.resetted == true) {
_controller.text = "";
}
return Material(
elevation: this.elev,
shadowColor: Colors.black,
borderRadius: new BorderRadius.circular(15),
animationDuration: new Duration(milliseconds: 500),
child: new TextField(
focusNode: _focusNode,
keyboardAppearance: Brightness.light,
style: Theme.of(context).textTheme.headline5,
controller: _controller,
keyboardType: TextInputType.number,
textAlign: TextAlign.end,
inputFormatters: <TextInputFormatter>[
LengthLimitingTextInputFormatter(8),
_whichLabel(widget.label),
],
decoration: new InputDecoration(
enabledBorder: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(15),
borderSide: new BorderSide(width: 1.2, color: CliniLiliac300),
),
focusedBorder: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(15),
borderSide: new BorderSide(width: 2.5, color: CliniLiliac300),
),
filled: true,
fillColor: Colors.white,
hintText: "0.0",
hintStyle: new TextStyle(fontSize: 15, color: Colors.black, fontFamily: "Montserrat"),
),
onChanged: (val) {
var cursorPos = _controller.selection;
val = val.replaceAll(",", ".");
if (val == "") {
provider.fields[_label] = 0.0;
} else if (double.parse(val) > provider.measure[_label] &&
provider.measure[_label] != 0) {
provider.fields[_label] % 1 == 0
? _controller.text = provider.fields[_label].toString().split(".")[0]
: _controller.text = provider.fields[_label].toString();
if (cursorPos.start > _controller.text.length) {
cursorPos = new TextSelection.fromPosition(
new TextPosition(offset: _controller.text.length),
);
}
_controller.selection = cursorPos;
} else {
provider.fields[_label] = double.parse(val);
}
provider.calculateResultRA();
},
),
);
}),
) : SizedBox();
}
Use TextFormField instead of TextField. TextFormField has several callbacks like validator, onSaved, onChanged, onEditingComplete, onSubmitted, ...
You can connect all your TextFormFields by wrapping it in a Form. This form should be given a GlobalKey so that you can identify the Form and call methods on FormState.
final _form = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
// ...
return Form(
key: _form,
child: // build Material with TextFormFields
);
}
Now to call onSaved on each TextFormField, you can call _form.currentState().save(). To reset every TextFormField you can call _form.currentState().reset().
You can get more information about how to build a Form and the functions you can call on FomState here:
https://flutter.dev/docs/cookbook/forms/validation
https://api.flutter.dev/flutter/widgets/FormState-class.html

text with \n and unicode literals saved in mysql do not work when displayed

I store a text string with \n and unicode literals like \u2022 in mysql, then retrieve it with http api call on flutter. When displaying it with Text widget, these escaped symbles do not show as expected. When I directly pass the string , it works. Could anyone help me out?
child: Column(
children: <Widget>[
Text(prompt.prompt_body, //This variable is from http call which does not work
textAlign: TextAlign.left,
style:TextStyle(
color: Colors.black,
fontSize: 13,
fontWeight: FontWeight.bold,
fontStyle: FontStyle.italic
)),
Divider(),
Text("You live in a room in college which you share with another student.However, there are many problems with this arrangement and you find it very difficult to work.\n\nWrite a letter to the accommodation officer at the college. In the letter,\n\n \u2022 describe the situation\n \u2022 explain your problems and why it is difficult to work\n \u2022 say what kind of accommodation you would prefer", //this part works
textAlign: TextAlign.left,
style:TextStyle(
color: Colors.black,
fontSize: 13,
fontWeight: FontWeight.bold,
fontStyle: FontStyle.italic
))
],
),
emulator screenshot
In response to Gunter's query, I add the following code on api call:
class PromptModel {
int id;
String prompt_body;
String prompt_image;
PromptModel(this.id, this.prompt_body, this.prompt_image);
PromptModel.fromJson(Map<String, dynamic> parsedJson) {
id = parsedJson['id'];
prompt_body = parsedJson['prompt_body'];
prompt_image = parsedJson['prompt_image'];
}
}
....
class PromptListPageState extends State<PromptListPage> {
int counter = 0;
List<PromptModel> prompts = [];
void fetchImage() async {
counter++;
var response =
await get('http://10.0.2.2:8080/TestPrompt');
var promptModel = PromptModel.fromJson(json.decode(response.body));
setState(() {
prompts.add(promptModel);
});
}
The following is the response of the api call:
{"id":1,"prompt_body":"You live in a room in college which you share with another student.However, there are many problems with this arrangement and you find it very difficult to work.\\n\\nWrite a letter to the accommodation officer at the college. In the letter,\\n\\n \\u2022 describe the situation\\n \\u2022 explain your problems and why it is difficult to work\\n \\u2022 say what kind of accommodation you would prefer","prompt_image":"http://10.0.2.2:8080/test.jpg"}
I solved the problem by inputting the string from flutter using TextFormField. directly inserting the text on database side is tricky. The code is as below:
Widget build(context) {
return MaterialApp(
home: Scaffold(
body: Form(
key: formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextFormField(
controller: myController,
maxLines: 5,
validator: (val) =>
(val == null || val.isEmpty) ? "请输入商品名称" : null,
decoration: const InputDecoration(
//icon: Icon(Icons.person),
hintText: 'add the prompt here:',
labelText: 'Prompt content',
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.teal)),
),
onSaved: (val) => this.content = val,
),
new Container(
margin: const EdgeInsets.only(top: 10.0),
child: new RaisedButton(
onPressed: _save,
child: new Text('Save'),
),
)
]),
),
appBar: AppBar(
title: Text('Add Essay Prompt'),
),
),
);
}
}