setState() or markNeedsBuild() called during build Query Widget - flutter

I have a problem with Graphql Flutter.
I am trying to display a search list retrieved with graphql.
But flutter tells me:
This widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
I added some Future Builder to avoid this kind of issue but unfortunately it doesn't seem to work
this is my code:
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Flexible(
flex: 5,
child: AnimatedContainer(
duration: Duration(milliseconds: 500),
padding: EdgeInsets.symmetric(horizontal: 25),
height: 42.0,
width: width,
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(20.0),
color: const Color(0xffffffff),
boxShadow: [
BoxShadow(
color: const Color(0x29000000),
offset: Offset(0, 0),
blurRadius: 12,
),
],
),
child: Form(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Flexible(
flex: 1,
child: Container(
width: 17.0,
height: 17.0,
decoration: BoxDecoration(
image: DecorationImage(
image: const AssetImage(
'assets/images/XDSearch.png'),
fit: BoxFit.cover,
),
),
),
),
Flexible(
flex: 6,
child: TextFormField(
onChanged: (value){
setState(() {
textSearch = value;
});
},
keyboardType: TextInputType.emailAddress,
decoration: const InputDecoration(
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
disabledBorder: InputBorder.none,
border: InputBorder.none,
hintText: 'Recherche'
),
style: TextStyle(
fontFamily: 'Roboto',
fontSize: 16,
color: const Color(0x8c000000),
fontWeight: FontWeight.w700,
),
textAlign: TextAlign.left,
focusNode: _focus,
),
)
],
),
),
),
),
clickOnBar == false ? Flexible(
flex: 1,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Container(
width: 30.0,
height: 30.0,
margin: EdgeInsets.fromLTRB(0, 0, 0, 0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15.0),
image: DecorationImage(
image: const AssetImage('assets/images/XDProfil.png'),
fit: BoxFit.fill,
),
),
)
],
),
) : Container()
],
),
textSearch != null && textSearch != 'undefined' && textSearch.isNotEmpty ? FutureBuilder(
builder: (context, projectSnap) {
return Query(
options: QueryOptions(
documentNode: gql("""
query getListSearch(\$text : String!){
listSearchProPages(text: \$text) {
categorie {
idCat
title
}
subCat {
idSubCat
title
}
pagePro {
idPagesPro
title
}
}
}
"""
),
variables: <String, dynamic>{
"text": textSearch,
},
pollInterval: 10
),
builder: (QueryResult result, {VoidCallback refetch, FetchMore fetchMore}){
print(result);
if (result.hasException) {
return Text(result.exception.toString());
}
if (result.loading) {
return Text('Loading');
}
var tmpObject = {
"categorie": result.data['listSearchProPages'].first['categorie'],
"subCat": result.data['listSearchProPages'].first['subCat'],
"pagePro": result.data['listSearchProPages'].first['pagePro'],
};
return FutureBuilder(
future: updateListSearch(tmpObject),
builder: (context, projectSnap){
if(tmpObject.length > 0) {
ListView.builder(
itemCount: tmpObject.length,
itemBuilder: (context, index) {
print(tmpObject);
final repository = tmpObject[index];
print(repository["categorie"]
.first['title']);
return Text(
repository["categorie"]
.first['title']);
}
);
}else {
return Container();
}
return Container();
}
);
},
);
}
) : Container()
],
),
Do you have the solution ?

Please do not create a new future on every call of the build method as you do now.
You need to create a future once (or maybe more often, but certainly not on every build) and then use that future in your build method:
Create a variable of your future type in your state class.
In your initState method, create the future, by assigning the result of updateListSearch(tmpObject) to your variable.
In your build method, use the variable as your parameter for the future in the FutureBuilder.

Related

I am using Getx for statemanagement, when I add data to server it doesn't appear newer data in listview until hot restart while list view is in Obx

I am working on an app. It's working fine with the rest API to get data from the server. But when I try to add data to the server newer data doesn't appear in the list. Here is my code for view and controller class.
View class code. It is in stateless widget
Expanded(
child: Obx(() {
if (controller.isLoading.value) {
return Center(child: LoadingBar());
} else {
return controller.profilesList.length == 0
? Center(child: Text("No Service Found"))
: ListView.builder(
physics: ScrollPhysics(),
shrinkWrap: true,
itemCount: controller.profilesList.length,
itemBuilder: (context, index) {
return Card(
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(5))),
clipBehavior: Clip.antiAlias,
child: Container(
height: 100,
child: Row(
children: [
Padding(
padding: const EdgeInsets.all(2.0),
child: Container(
width: 100,
// height: 100,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(5)),
image: DecorationImage(
image: NetworkImage(
'http://192.168.43.113:4000/${controller.profilesList[index].shopImage}'),
fit: BoxFit.cover))),
),
Flexible(
child: Padding(
padding: const EdgeInsets.all(2.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
controller
.profilesList[index].shopName,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 15),
),
Text(
controller
.profilesList[index].address,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: Colors.black54)),
Text('9:AM-10:PM Mon-Sat',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: OrdersTextStyle
.servicesTextStyle()),
Align(
alignment: Alignment.bottomLeft,
child: Container(
decoration: BoxDecoration(
color: CustomColors.lightRed,
// border: Border.all(width: 1),
borderRadius: BorderRadius.all(
Radius.circular(5)),
),
child: Padding(
padding:
const EdgeInsets.all(3.0),
child: Text(
controller
.profilesList[index]
.providercategories
.providerCatName,
style: TextStyle(
color: Colors.white,
fontWeight:
FontWeight.normal),
),
),
// height: 25,
// width: 70,
),
)
],
),
),
)
],
),
),
);
},
);
}
}),
Here is my controller class
class ProviderProfilesController extends GetxController {
var id = ''.obs;
var isLoading = true.obs;
var profilesList = <ProfileModel>[].obs;
void getProfilesData(String id) async {
isLoading(true);
try {
var list = await ApiServices.getProvidersprofileData(id);
if (list != null) {
profilesList.value = list;
}
} finally {
isLoading(false);
}
//profilesList.refresh();
}
#override
void onInit() {
super.onInit();
getProfilesData(id.value);
}
}
I think the problem here is that you are using profileList.value to update the list and the right way to do that is adding items to the list using the List's functions like in the following examples:
final abc = [0,1,2].obs;
abc.add(12);
In your case you can use the following code once you want to add a whole list:
abc.addAll(['12','234','1465']);
Let me know if this don't work because there is also the update and refresh functions on getx which solved my problem sometimes. I'll answer here asap.

[Flutter]How to import image from gallery dynamically

I am a new flutter learner and trying to create my first app. My problem is...
(1). I use a method to build a place(widget) for image which will come from gallery or camera.
void _showPicker(context) {
showModalBottomSheet(
context: context,
builder: (BuildContext bc) {
return SafeArea(
child: Container(
child: new Wrap(
children: <Widget>[
new ListTile(
leading: new Icon(Icons.photo_library),
title: new Text('Gallery'),
onTap: () {
_imgFromGallery();
Navigator.of(context).pop();
}),
new ListTile(
leading: new Icon(Icons.photo_camera),
title: new Text('Camera'),
onTap: () {
_imgFromCamera();
Navigator.of(context).pop();
},
),
],
),
),
);
});
}
(2). I created a method to import image by using image_picker package.
Future _imgFromGallery() async {
final pickedImage =
await _picker.getImage(source: ImageSource.gallery, imageQuality: 50);
setState(() {
if (pickedImage != null) {
this._image = new File(pickedImage.path);
}
});
}
(3). I create a button which if pressed, will call method (1) and medthod (1) contained medthod (2).
(4). When I added the first image, everything fine but, when I add the second image, the first image also changed to the second
image
So, could you please help me for figure out of this problem?
Sorry that I didn't share the code that call _showPicker (function for displayed image) here is the code...please focus at GestureDetector(...),
_createListStepRow(String item, int index) {
return Column(children: [
Container(
margin: EdgeInsets.only(top: 3),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: new BorderRadius.circular(15),
border: Border.all(color: Colors.black)),
child: Column(children: [
Row(crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[
Container(
width: 1175.0.w,
child: TextField(
autofocus: this.autoFocus,
cursorColor: Colors.black,
decoration: InputDecoration(
prefixIcon: Icon(
Icons.restaurant_outlined,
color: Constants.primaryColor,
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(15),
borderSide: BorderSide(color: Colors.white, width: 1.5),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(color: Colors.white, width: 0),
),
contentPadding: EdgeInsets.symmetric(vertical: 8),
hintText: item,
floatingLabelBehavior: FloatingLabelBehavior.never,
)),
),
IconButton(
icon: Icon(Icons.delete),
onPressed: () {
setState(() {
_itemsStep.removeAt(index);
});
},
),
]),
GestureDetector(
onTap: () async {
_showPicker(context);
},
child: Container(
padding: EdgeInsets.all(8),
// height: 800.0.h,
width: double.infinity,
decoration: BoxDecoration(
color: Colors.grey[200],
// image: DecorationImage(
// image: AssetImage('assets/images/food1.jpg'),
// fit: BoxFit.fill,
// ),
shape: BoxShape.rectangle,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
new Column(children: [
Container(
// height: 200.0.h,r
child: _image == null
? _nullImage
: Image.file(_image, fit: BoxFit.contain),
),
// Text(
// 'Click to Add Step Image',
// style: GoogleFonts.poppins(fontSize: 14),
// ),
]),
]),
),
),
SizedBox(height: 60.0.h),
]),
),
SizedBox(height: 30.0.h),
]);
}
First off, you're not storing the images. You're basically choosing the latest one. Lets fix that. Find where you've declared var _image; and change that to final List<File> _images;.
Next, change the Column in the GestureDetector in _showPicker to this:
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
new ListView.builder(
itemBuilder: (context, index) {
return Container(
// height: 200.0.h,r
child: _images[index] == null
? _nullImage
: Image.file(_images[index], fit: BoxFit.contain),
);
},
itemCount: _images.length,
// Text(
// 'Click to Add Step Image',
// style: GoogleFonts.poppins(fontSize: 14),
// ),
)
],
),
If the code you gave was working as you said before, this should probably work.

Why is selected value not reflecting in showModalBottomSheet with flutter?

First of all, I created a designed bottom sheet, In which, there are two lists to show numbers(left side) and options(hour, day, week, month) with the help of CupertinoPicker widget,
Numbers will depend on what option I select, If I select the hour, numbers of the left side should be 1-24, and if I select week, numbers should be 1-4, I select the day, numbers should be 1-30 and last I select month number should be 1-12.
Code :
All Lists variable:
List<String> reminderDay = ['hour','day','week','month'];
List<String> reminderHoursVal =['1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24'];
List<String> reminderDaysVal =['1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31'];
List<String> reminderMonthsVal =['1','2','3','4','5','6','7','8','9','10','11','12'];
List<String> reminderWeeksVal =['1','2','3','4'];
String selectedReminderVal='1';
String selectedReminderDay ='hour';
Code of bottom sheet:
addReminder(){
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return AnimatedPadding(
padding: MediaQuery.of(context).viewInsets,
duration: const Duration(milliseconds: 100),
curve: Curves.decelerate,
child: Container(
padding: const EdgeInsets.only(top:8,right: 8, left:8,bottom: 8),
height: MediaQuery.of(context).size.height/2,
// color: Colors.transparent,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30),
topRight: Radius.circular(30)
)
),
child: Container(
child: Column(
// mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height:10),
Text("Set a reminder",
style: TextStyle(
fontSize:18,
fontWeight:FontWeight.bold,
color: Colors.grey
),
),
SizedBox(height:20),
Container(
margin: const EdgeInsets.only(left: 10, right: 10),
height: MediaQuery.of(context).size.height/4,
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(10)
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: CupertinoPicker(
scrollController: new FixedExtentScrollController(
initialItem: 0,
),
itemExtent: 30,
backgroundColor: Colors.grey[100],
onSelectedItemChanged: (int val) {
setState(() {
if(selectedReminderDay=='day'){
selectedReminderVal = reminderDaysVal[val];
}else if(selectedReminderDay=='week'){
selectedReminderVal = reminderWeeksVal[val];
}else if(selectedReminderDay=='month'){
selectedReminderVal = reminderMonthsVal[val];
}else{
selectedReminderVal = reminderHoursVal[val];
}
print("selectedReminderVal:$selectedReminderVal");
});
},
children:selectedReminderDay=='day'?reminderDaysVal
:selectedReminderDay=='week'?reminderWeeksVal
:selectedReminderDay=='month'?reminderMonthsVal:reminderHoursVal// ['hour','day','week','month']; reminderHoursVal
.map(
(item) => Center(
child: Text(
item,
style: TextStyle(
fontSize: 16,
// fontWeight:FontWeight.bold,
),
),
),
)
.toList()),
),
Expanded(
child: CupertinoPicker(
scrollController: new FixedExtentScrollController(
initialItem: 0,
),
itemExtent: 30,
backgroundColor: Colors.grey[100],
onSelectedItemChanged: (int val) {
setState(() {
selectedReminderDay = reminderDay[val];
print("selectedReminderDay:$selectedReminderDay");
});
},
children: reminderDay
.map(
(item) => Center(
child: Text(
item,
style: TextStyle(
fontSize: 16,
// fontWeight:FontWeight.bold,
),
),
),
)
.toList()),
),
])
),
SizedBox(height:15),
// selectedVal!=null?Text(selectedVal.toString()):Container()
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("You'll get the reminder"),
Text('$selectedReminderVal $selectedReminderDay before the event')
],
),
SizedBox(height:25),
Padding(
padding: const EdgeInsets.only(left: 10, right: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
InkWell(
onTap: (){
Navigator.pop(context);
},
child: Text("Cancel",
style: TextStyle(
fontSize: 18,
color: Colors.blue,
fontWeight: FontWeight.bold
),
),
),
InkWell(
onTap: (){
Navigator.pop(context);
},
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(8)
),
width: MediaQuery.of(context).size.width/5,
height: MediaQuery.of(context).size.height/25 ,
child: Text("Save", style:TextStyle(
color: Colors.white,
fontSize: 19
)),
),
)
],
),
)
],
),
)
),
);
},
);
}
Screenshot:
This is because the state you are setting is different from the state in the modal bottom sheet.
Right now, when you are calling setState, you are actually rebuilding the stateful widget under the modal bottom sheet.
To fix this, just wrap your bottom sheet in a Stateful Builder.
StatefulBuilder(
builder: (context, setState) {
return AnimatedPadding(
padding: MediaQuery.of(context).viewInsets,
duration: const Duration(milliseconds: 100),
curve: Curves.decelerate,
child: Container(
padding: const EdgeInsets.only(top:8,right: 8, left:8,bottom: 8),
height: MediaQuery.of(context).size.height/2,
// color: Colors.transparent,
decoration: BoxDecoration(
color: Colors.white,
....
when we create new context widgets in existing state there states become different, bottomSheets are similar to dialogBox with new context and builder build a completely new widget out of the parent state, to create its own stateful state Wrap it with the stateful builder and user its own setState to change anything in this context not the parent one
eg:
StatefulBuilder(
builder: (context, setStateChild) {
return AnimatedPadding(...
Expanded(
child: CupertinoPicker(
scrollController: new FixedExtentScrollController(
initialItem: 0,
),
itemExtent: 30,
backgroundColor: Colors.grey[100],
onSelectedItemChanged: (int val) {
setStateChild(() {
selectedReminderDay = reminderDay[val];
print("selectedReminderDay:$selectedReminderDay");
});
},);
child: ... ),
}

How to use dynamic TextField Controller inside ExpansionTile Flutter

Being new to Flutter, I have created a ExpansionTile (see below screenshot) and have added EditField as a Child.
Here ExpansioTile and comment EditField is created dynamically based on server response.
Inside each ExpansionTile there will be multiple TextFields
Now how do I add TextFieldController dynamically and get all values upon button click?
ExpansionTile Code
FutureBuilder(
future: _fetchQuestions(),
builder: (context, AsyncSnapshot snapshot){
if (snapshot.hasError) {
return Text('Error ${snapshot.error}');
}
else if (snapshot.hasData) {
return new Padding(
padding: EdgeInsets.fromLTRB(20.0, 5.0, 20.0, 0.0),
child: Container(
child: PageView.builder(
physics: new NeverScrollableScrollPhysics(),
controller: _pageController,
itemCount: snapshot.data[0].auditAreas.length,
onPageChanged: (int index) {
print('## on page changed $index');
},
itemBuilder: (BuildContext context, int index) {
print('## index '+index.toString());
List<QuestionGroups> listQuestionsGrp = snapshot.data[0].auditAreas[index].questionGroups;
print('## question grp list size == '+listQuestionsGrp.length.toString());
List<Widget> list = new List<Widget>();
for (int i=0; i<listQuestionsGrp.length; i++){
bloc.newFields();
List<Widget> listItemWidgets = new List<Widget>();
// below list(listAuditQues) is used to get the questions from question groups
List<AuditQuestions> listAuditQues = listQuestionsGrp[i].auditQuestions;
for (int j=0; j<listAuditQues.length; j++){
print('# audit question id == '+listAuditQues[j].auditQuestionId.toString());
// _mapController.map(listAuditQues[j].auditQuestionId, _textController);
// _controllers.add(TextEditingController());
List<AuditQuestionAnswers> listAuditQuestAns = listAuditQues[j].auditQuestionAnswers;
print('## list of question and answers used for radio buttons == '+listAuditQuestAns.length.toString());
List<Widget> listTitleOfRadioButtons = new List<Widget>();
for (int k=0; k<listAuditQuestAns.length; k++){
// here have to get the list of radio button text and append below inside the column
List<AuditQuestionAnswerOptionParameters> listQuesAnsParameter = listAuditQuestAns[k].auditQuestionAnswerOptionParameters;
print('## list question answer list size == '+listQuesAnsParameter.length.toString());
List<Widget> listRadioButtons = new List<Widget>();
for (int m=0; m<listQuesAnsParameter.length; m++){
listRadioButtons.add(
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new Radio(value: 0, groupValue: null, onChanged: null, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,),
new Text(listQuesAnsParameter[m].answerOptionParameterTitle,style: TextStyle(
fontSize: 12.0
))
],
)
);
}
listTitleOfRadioButtons.add(
Column(
children: <Widget>[
Align(
alignment: Alignment.centerLeft,
child: Container(
margin: EdgeInsets.fromLTRB(10.0, 4.0, 0.0, 4.0),
child: Text(listAuditQuestAns[k].auditEntityTitle,
style: TextStyle(fontSize: 13.5),),
),
),
Row(
children: listRadioButtons,
)
],
)
);
}
// Here adding expansion item content
listItemWidgets.add(
Column(
children: <Widget>[
Row(
// mainAxisAlignment: message.author == username ? MainAxisAlignment.end : MainAxisAlignment.start,
//this will determine if the message should be displayed left or right
children: [
Flexible(
//Wrapping the container with flexible widget
child: Container(
padding: EdgeInsets.all(6.0),
margin: EdgeInsets.all(4.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4.0),
border: Border.all(color: Colors.black)
),
child: Row(
children: <Widget>[
Flexible(
//We only want to wrap the text message with flexible widget
child: Container(
child: Text(
listAuditQues[j].title,
)
)
),
],
)
),
)
]
),
Column(
children: listTitleOfRadioButtons
),
Container(
height: 80,
margin: EdgeInsets.all(4.0),
child: new ConstrainedBox(
constraints: BoxConstraints(
maxHeight: 80.0,
),
child: new Scrollbar(
child: new SingleChildScrollView(
scrollDirection: Axis.vertical,
reverse: true,
child: SizedBox(
height: 80.0,
child: new TextFormField(
// controller: _controllers[j],
maxLines: 60,
decoration: new InputDecoration(
labelText: "Comment",
focusedBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Colors.black, width: 0.8)),
enabledBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Colors.black, width: 0.8)),
),
),
),
),
),
),
),
new Container(
margin: EdgeInsets.all(4.0),
padding: EdgeInsets.fromLTRB(2.0, 4.0, 0.0, 0.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
GestureDetector(
onTap: (){
print('## index of pager $index');
print('## index of main lopp $i');
print('## index of lopp $j');
},
child: new Icon(Icons.camera_alt,
size: 22.0, color: Colors.black),
),
new Icon(Icons.attach_file,
size: 22.0, color: Colors.black),
new Text("(4)", style: TextStyle(fontSize: 12.0))
],
),
),
Container(
margin: EdgeInsets.all(4.0),
child: Divider(height: 4.0,color: Colors.black),
)
],
)
);
}
// Main Title of expansion list adding here
list.add(customExpansionTile.ExpansionTile(
headerBackgroundColor: Colors.grey,
backgroundColor: Colors.white,
iconColor: Colors.black,
title: Text(listQuestionsGrp[i].title, style: TextStyle(
fontSize: 14.0
)),
children: listItemWidgets
));
}
return new ListView(
children: list,
);
// return _buidlExpnsionListTile(snapshot.data[0]);
/*List<AuditAreas> auditAreaList = snapshot.data[index].auditAreas;
print('## audit area list size == ${auditAreaList.length}');
return Text('Screen index == '+index.toString());*/
},
),
),
);
}
else{
return CircularProgressIndicator();
}
},
)
Please help me out..
Initialize it:
TextEditingController controller;
On initState:
#override
initState() {
super.initState();
controller = new TextEditingController();
}
Controller example in TextFormField:
new TextFormField(
validator: (senha) =>
senha.isEmpty ? 'Por favor insira sua senha' : null,
onSaved: (senha) => _pass = senha,
obscureText: true,
textAlign: TextAlign.start,
decoration: InputDecoration(
prefixIcon: Icon(
Icons.vpn_key,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0)),
filled: true,
hintText: 'Senha',
),
controller: controller,
),
To access the TextFormField text just make controller.text

How to resolve overflow with widget in flutter?

I have an image of an issue that is overflowing by 17 pixels.
& I'm unable to resolve it?
first of all, what I did..!!!
I took a Row()widget and wrapped with Container() & in that Row() took two Expanded() widget. one is for TextField() and another is for CountryPickerDropdown().
I have used country_pickers plugin
CODE:
new Container(
width: MediaQuery.of(context).size.width,
padding: const EdgeInsets.only(left: 10.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(5.0)),
border: Border.all(color: Colors.blue)
),
child: Row(
children: <Widget>[
Expanded(
child: CountryPickerDropdown(
initialValue: 'in',
itemBuilder: _buildDropdownItem,
onValuePicked: (Country country) {
isCountryCodeSelected=true;
print("${country.name}");
print("${country.phoneCode}");
print("${country.isoCode}");
print("+${country.phoneCode}(${country.isoCode})");
setState(() {
countryCode= country.phoneCode;
});
},
),
),
Expanded(
child: TextField(
keyboardType: TextInputType.phone,
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Telephone Number",
),
onChanged: (value){
setState(() {
phoneValue=value;
});
print("phoneNumbe:$phoneNo");
this.phoneNo = isCountryCodeSelected ? "+" + countryCode + value : "+91" + value ;
print("phoneNo="+phoneNo);
},
),
)
],
)
),
Widget for Contry code and their national Flag image:
Widget _buildDropdownItem(Country country) => Container(
child: Row(
children: <Widget>[
CountryPickerUtils.getDefaultFlagImage(country),
SizedBox(
width: 8.0,
),
Text("+${country.phoneCode}(${country.isoCode})"),
],
),
);
Suspecting that your countryselector widget needs to have expanded childs and the text overflow.
Widget _buildDropdownItem(Country country) => Row(
children: <Widget>[
Expanded(child: Container(
margin: EdgeInsets.only(right: 8),
child: CountryPickerUtils.getDefaultFlagImage(country)),),
Expanded(child: Text(
"+${country.phoneCode}(${country.isoCode})",
overflow: Overflow.Eclipse
),)
],
);
Just remove the Expanded widget above the CountryPickerDropdown widget
If we set Expanded widget on both the child, Both will try to take the max width. So if we just set expanded widget on textfield only, textfield will take the remaining width of the screen. Below is the working code snippet with output of screenshot of small device.
Container(
width: MediaQuery.of(context).size.width,
padding: const EdgeInsets.only(left: 10.0),
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(5.0)),
border: Border.all(color: Colors.blue)),
child: Row(
children: <Widget>[
CountryPickerDropdown(
initialValue: 'in',
itemBuilder: _buildDropdownItem,
onValuePicked: (Country country) {
print("${country.name}");
print("${country.phoneCode}");
print("${country.isoCode}");
print("+${country.phoneCode}(${country.isoCode})");
},
),
Expanded(
child: TextField(
keyboardType: TextInputType.phone,
decoration: const InputDecoration(
border: InputBorder.none,
hintText: "Telephone Number 14655656556",
),
onChanged: (value) {},
),
)
],
)),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
The Wrap is replaced by Row and width of textfield reduced Hope this helps. Please let me know if something went wrong.
new Container(
padding: EdgeInsets.only(left:10.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(5.0)),
border: Border.all(color: Colors.blue)
),
child: Row(
children: <Widget>[
Container(
child: CountryPickerDropdown(
initialValue: 'in',
itemBuilder: _buildDropdownItem,
onValuePicked: (Country country) {
isCountryCodeSelected=true;
print("${country.name}");
print("${country.phoneCode}");
print("${country.isoCode}");
print("+${country.phoneCode}(${country.isoCode})");
setState(() {
countryCode= country.phoneCode;
});
},
),
width: MediaQuery.of(context).size.width/2-30.0,
),
Container(
width: MediaQuery.of(context).size.width/2-30.0,
child: TextField(
keyboardType: TextInputType.phone,
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Telephone Number",
),
onChanged: (value){
setState(() {
phoneValue=value;
});
print("phoneNumbe:$phoneNo");
this.phoneNo = isCountryCodeSelected ? "+" + countryCode + value : "+91" + value ;
print("phoneNo="+phoneNo);
},
),
),
],
)
)
The Wrap is replaced by Row and width of textfield reduced Hope this helps. Please let me know if something went wrong.
Try using this approach ....(In the text field you can add your phone no and in the orange and cyan color flex you can add your country picker)
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
resizeToAvoidBottomPadding: false,
body: SafeArea(
child: Center(
child: Column(children: [
Expanded(
flex: 25,
child: Column(children: [
Expanded(
flex: 1,
child: Container(
color: Colors.red,
),
),
Expanded(
flex: 2,
child: Column(
children: [
Expanded(
flex: 1,
child: Container(
color: Colors.blue,
),
),
Expanded(
flex: 1,
child: Row(
children: [
Expanded(
flex: 1,
child: Row(
children: [
Expanded(
flex: 1,
child: Container(
color: Colors.orange,
),
),
Expanded(
flex: 1,
child: Container(
color: Colors.cyan,
),
),
],
)),
Expanded(
flex: 1,
child: TextField(
style: TextStyle(color: Colors.black),
),
),
],
)),
Expanded(
flex: 1,
child: Container(
color: Colors.blue,
),
),
],
),
),
Expanded(
flex: 1,
child: Container(
color: Colors.pink,
),
)
])),
Expanded(
flex: 3,
child: Container(
color: Colors.blue,
),
)
])))));
}
}
Expanded(
flex:1
child: CountryPickerDropdown(
initialValue: 'in',
itemBuilder: _buildDropdownItem,
onValuePicked: (Country country) {
isCountryCodeSelected=true;
print("${country.name}");
print("${country.phoneCode}");
print("${country.isoCode}");
print("+${country.phoneCode}(${country.isoCode})");
setState(() {
countryCode= country.phoneCode;
});
},
),
),
Expanded(
flex:2
child: TextField(
keyboardType: TextInputType.phone,
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Telephone Number",
),
onChanged: (value){
setState(() {
phoneValue=value;
});
print("phoneNumbe:$phoneNo");
this.phoneNo = isCountryCodeSelected ? "+" + countryCode + value : "+91" + value ;
print("phoneNo="+phoneNo);
},
),)