i m new to flutter and am trying to make a Responsive app , i have a textfield and i wanted to add a dropdown list next to it it s working but it shows a error " right overflowed by 150 pixels" even tho i m using the Expanded widget in the child . the error is in both dropdownlists
thank you for ur help in advance
import '../Classes/demandes.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import '../data/menu_item.dart';
import '../Classes/menu.dart';
import '../data/logout.dart';
class Demandes extends StatefulWidget {
#override
_demande createState() => _demande();
}
class _demande extends State<Demandes> {
String dropdownValue = 'Assets';
String dropdownValue1 = 'Locations';
Future<Demandes?> submitData(String description, ASSETNUM, location,
DESCRIPTION_LONGDESCRIPTION) async {
var respone = await http.post(
Uri.parse(
'http://9080/maxrest/rest/mbo/sr/?_lid=azizl&_lpwd=max12345m&_format=json'),
body: {
"description": description,
"ASSETNUM": ASSETNUM,
"location": location,
"DESCRIPTION_LONGDESCRIPTION": DESCRIPTION_LONGDESCRIPTION,
});
var data = respone.body;
print(data);
if (respone.statusCode == 201) {
dynamic responseString = respone.body;
azizFromJson(responseString);
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("Demande de service Cree")));
} else
return null;
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("error")));
return null;
}
late Demandes? _demandes;
TextEditingController descriptionController = TextEditingController();
TextEditingController ASSETNUMController = TextEditingController();
TextEditingController locationController = TextEditingController();
TextEditingController DESCRIPTION_LONGDESCRIPTIONController =
TextEditingController();
Widget DescriptionTextField() {
return TextField(
decoration: InputDecoration(
// labelText: "Description",
border: OutlineInputBorder(borderRadius: BorderRadius.circular(10)),
),
controller: descriptionController,
);
}
Widget AssetTextField() {
return TextField(
decoration: InputDecoration(
// labelText: "Asset",
border: OutlineInputBorder(),
),
controller: ASSETNUMController,
);
}
Widget DeatialsTextField() {
return TextField(
decoration: InputDecoration(
// labelText: "Details",
border: OutlineInputBorder(),
),
maxLines: 10,
controller: DESCRIPTION_LONGDESCRIPTIONController,
);
}
Widget LocationTextField() {
return TextField(
decoration: InputDecoration(
// labelText: "Location",
border: OutlineInputBorder(),
),
controller: locationController,
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Creation Demande de service'),
actions: [
PopupMenuButton<MenuItem>(
onSelected: (item) => onSelected(context, item),
itemBuilder: (context) =>
[...MenuItems.itemsFirst.map(buildItem).toList()],
)
],
),
body: ListView(
padding: EdgeInsets.all(8),
// ignore: prefer_const_literals_to_create_immutables
children: [
ListTile(
title: Text("Description"),
),
DescriptionTextField(),
ListTile(
title: Text("Details"),
),
DeatialsTextField(),
ListTile(title: Text("Asset")),
Row(
children: <Widget>[
Expanded(
child: AssetTextField(),
),
const SizedBox(
width: 20,
),
Expanded(
child: DropdownButton<String>(
value: dropdownValue,
icon: const Icon(Icons.arrow_drop_down),
elevation: 16,
style: const TextStyle(color: Colors.blue),
underline: Container(
height: 2,
color: Color.fromARGB(255, 0, 140, 255),
),
onChanged: (String? newValue) {
setState(() {
dropdownValue = newValue!;
});
},
items: <String>[
'Assets',
'100014 moteur 3',
'100027 Système de freinage 1',
'12500 Overhead Crane #2',
'13110 Feeder System',
'13120 Bottom Sealing System',
'13130 Stripper System',
'13140 Conveyor System- Pkg. Dept.',
'13141 Elevator Rails And Drainpan Assembly',
'13142 Carton Escapement Assembly #2',
'13143 Chain Wash Assembly',
].map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
)),
],
),
ListTile(
title: Text("Location"),
),
Row(
children: <Widget>[
Expanded(
child: LocationTextField(),
),
const SizedBox(
width: 20,
),
Expanded(
child: DropdownButton<String>(
value: dropdownValue1,
icon: const Icon(Icons.arrow_drop_down),
elevation: 16,
style: const TextStyle(color: Colors.blue),
underline: Container(
height: 2,
color: Color.fromARGB(255, 0, 140, 255),
),
onChanged: (String? newValue) {
setState(() {
dropdownValue1 = newValue!;
});
},
items: <String>[
'Locations',
'100014 moteur 3',
'10002 7 Système de freinage 1',
'12500 Overhead Crane #2',
'13110 Feeder System',
'13120 Bottom Sealing System',
'13130 Stripper System',
'13140 Conveyor System- Pkg. Dept.',
'13141 Elevator Rails And Drainpan Assembly',
'13142 Carton Escapement Assembly #2',
'13143 Chain Wash Assembly',
].map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
)),
],
),
const SizedBox(
width: 20,
),
Padding(padding: EdgeInsets.all(10)),
ElevatedButton(
onPressed: (() async {
String description = descriptionController.text;
String ASSETNUM = ASSETNUMController.text;
String location = locationController.text;
String DESCRIPTION_LONGDESCRIPTION =
DESCRIPTION_LONGDESCRIPTIONController.text;
Demandes? data = await submitData(description, ASSETNUM,
location, DESCRIPTION_LONGDESCRIPTION);
setState(() {
_demandes = data;
});
}),
child: Text("submit "),
)
],
));
}
}
Ok the only thing that you have to write is this :
Expanded(
child: DropdownButton<String>(
value: dropdownValue,
isExpanded: true, // this
[...]
),
),
Like the documentation say :
Set the dropdown's inner contents to horizontally fill its parent.
By default this button's inner width is the minimum size of its
contents. If [isExpanded] is true, the inner width is expanded to fill
its surrounding container.
Related
I want to display markers on a Flutter Map ('package:flutter_map/flutter_map.dart')
But all map markers take the same parameters when I add one.
When the user clicks on the map, a popup opens with fields to define the attributes of the marker.
These fields values are associated to class variables.
Is it because the Marker builder uses the pointers of the primitive variables and not their values?
Or it's because Dart understands primitive types as objects?
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';
import 'package:positioned_tap_detector_2/positioned_tap_detector_2.dart';
///
/// Widget that allows display intervention
///
class DisplayIntervention extends StatefulWidget {
const DisplayIntervention({Key? key}) : super(key: key);
#override
_DisplayInterventionState createState() => _DisplayInterventionState();
}
class _DisplayInterventionState extends State<DisplayIntervention> {
// Initialize map controller
late final MapController mapController;
// Size of the left panel
final int leftPaneProportion = 20;
// Map settings
List<Marker> map_markers = [];
List<Map> availableColors = [
{'name': 'Red', 'value': Colors.red},
{'name': 'Green', 'value': Colors.green},
{'name': 'Blue', 'value': Colors.blue},
{'name': 'Black', 'value': Colors.black},
];
// Map capture (start capture many points)
bool mapCapture = false;
// History of taps
List<LatLng> tapHistory = [];
// ---- END DRAWER SECTION ----- //
// ---- START NEW MARKER SECTION ----- //
final _markerFormKey = GlobalKey<FormState>();
String _markerLabelController = "";
IconData _markerTypeController = Icons.directions_car;
int _markerRotationController = 0;
double _markerSizeController = 30.0;
Color _markerColorController = Colors.red;
List<Map> availableVehicles = [
{'name': 'Car', 'value': Icons.directions_car},
{'name': 'Truck', 'value': Icons.local_shipping},
];
// ---- END NEW MARKER SECTION ----- //
#override
void initState() {
super.initState();
mapController = MapController();
}
void _handleTap(TapPosition tapPosition, LatLng latlng) {
tapHistory.add(latlng);
openMarkerPopup();
}
void computeMarker(){
print("Add new marker");
map_markers.add(
Marker(
width: _markerSizeController,
height: _markerSizeController,
point: tapHistory.last,
builder: (ctx) =>
Container(
child: Icon(_markerTypeController, color: _markerColorController, size: _markerSizeController),
),
));
setState(() {
map_markers;
});
}
openMarkerPopup(){
showDialog(context: context, builder: (BuildContext context) {
return AlertDialog(
scrollable: true,
title: Text('Add marker'),
content: Padding(
padding: const EdgeInsets.all(8.0),
child: Form(
key: _markerFormKey,
child: Column(
children: <Widget>[
TextFormField(
initialValue: _markerLabelController,
onChanged: (value) {
_markerLabelController = value;
},
decoration: const InputDecoration(
labelText: 'Label',
icon: Icon(Icons.abc_rounded),
),
),
DropdownButtonFormField(
decoration: const InputDecoration(
icon: Icon(Icons.border_color),
),
value: _markerTypeController,
items: availableVehicles.map((map) {
return DropdownMenuItem(
child: Text(map['name']),
value: map['value'],
);
}).toList(),
onChanged: (value) {
setState(() {
if (value != null){
_markerTypeController = value as IconData;
}
});
},
),
DropdownButtonFormField(
decoration: const InputDecoration(
icon: Icon(Icons.brush_rounded),
),
value: _markerColorController,
items: availableColors.map((map) {
return DropdownMenuItem(
child: Text(map['name']),
value: map['value'],
);
}).toList(),
onChanged: (value) {
setState(() {
if (value != null){
_markerColorController = value as Color;
}
});
},
),
TextFormField(
initialValue: _markerSizeController.toString(),
keyboardType: TextInputType.number,
onChanged: (value) {
_markerSizeController = double.parse(value);
},
decoration: const InputDecoration(
labelText: 'Size',
icon: Icon(Icons.expand_more),
),
),
TextFormField(
initialValue: _markerRotationController.toString(),
keyboardType: TextInputType.number,
onChanged: (value) {
_markerRotationController = int.parse(value);
},
decoration: const InputDecoration(
labelText: 'Angle',
icon: Icon(Icons.zoom_in_rounded),
),
)
],
),
),
),
actions: [
ElevatedButton(
child: Text("Back"),
onPressed: () {
Navigator.of(context).pop();
}),
ElevatedButton(
child: Text("Valid"),
onPressed: () {
computeMarker();
Navigator.of(context).pop();
}),
],
);
});
}
#override
Widget build(BuildContext context) {
return Flex(
direction: Axis.horizontal,
children: [
Flexible(
flex: leftPaneProportion,
child: Container(
color: Colors.white,
child: Scaffold(
resizeToAvoidBottomInset: true,
body: ListView(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
children: const <Widget>[
Card(
child: ListTile(
title: Text("Debug"),
trailing: Icon(
Icons.arrow_circle_right_outlined))),
],
))),
),
Flexible(
flex: 100 - leftPaneProportion,
child: FlutterMap(
mapController: mapController,
options: MapOptions(
center: LatLng(48.117266, -1.6777926),
zoom: 10,
onTap: _handleTap
),
layers: [
MarkerLayerOptions(
markers: map_markers
),
],
children: <Widget>[
TileLayerWidget(
options: TileLayerOptions(
urlTemplate:
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
subdomains: ['a', 'b', 'c'],
),
),
],
),
),
],
);
}
}
The problem came from the marker builder
By giving directly the global variable the builder uses the pointer.
While by passing the value via an intermediate variable the problem is solved.
Recently implemented a tagForm widget at "+" button press, I want to delete those widgets now at "delete" button press, but right now, even when I press the "delete" button, nothing happens.
How can I solve this?
Any help appreciated!
code:
import 'package:flutter/material.dart';
import '../database/firestoreHandler.dart';
import '../models/todo2.dart';
import '../widgets/dialogs.dart';
class TodoEdit extends StatefulWidget {
String? doctitle;
String? doctdescription;
String? docimage;
String? docid;
List? doctags;
TodoEdit({Key? key, this.doctitle, this.doctdescription, this.docimage, this.docid,this.doctags}) : super(key: key);
#override
_TodoEditState createState() => _TodoEditState();
}
class _TodoEditState extends State<TodoEdit> {
final _formKey = GlobalKey<FormState>();
final tcontroller = TextEditingController();
final dcontroller = TextEditingController();
final icontroller = TextEditingController();
var textEditingControllers = <TextEditingController>[];
//-----------------the list where the form is stored----------
var textformFields = <Widget>[];
void _addformWidget(controller) {
setState(() {
textformFields.add(tagForm(controller));
});
}
//------------------------------------------------------------------------
Widget tagForm(controller){
return TextFormField(
controller: controller,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: "Tag",
labelStyle: TextStyle(color: Colors.white60),
fillColor: Colors.black,
filled: true,
suffixIcon: IconButton(
icon:Icon(Icons.delete, color: Colors.white,),
//--------------------- doesn't work?-------------------
onPressed: (){
setState(() {
textformFields.remove(tagForm(controller));
});
},
--------------------------------------------------------------
)
),
);
}
//-----------------------------------------------------------
#override
void initState() {
super.initState();
tcontroller.text = widget.doctitle.toString();
dcontroller.text = widget.doctdescription.toString();
icontroller.text = widget.docimage.toString();
widget.doctags?.forEach((element) {
var textEditingController = new TextEditingController(text: element);
textEditingControllers.add(textEditingController);
//return textformFields.add(tagForm(textEditingController)
return _addformWidget(textEditingController);
//);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[900],
appBar: AppBar(
actions: [
IconButton(onPressed: (){
showDialog(
barrierDismissible: false,
context: context,
builder: (context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
title: Text('Delete TODO'),
actions: [
TextButton(
child: Text('Cancel'),
onPressed: () {
Navigator.pop(context);
},
),
TextButton(
child: Text('Delete'),
onPressed: () {
deleteData(widget.docid.toString(), context);
setState(() {
showSnackBar(context, 'todo "${widget.doctitle}" successfully deleted!');
});
},
),
],
);
},
);
},
icon: Icon(Icons.delete))
],
backgroundColor: Colors.grey[900],
title: Text("${widget.doctitle}"),
),
body: Container(
child: SafeArea(
child: Form(
key: _formKey,
child: Column(
children: [
SizedBox(height: 10),
TextFormField(
controller: tcontroller,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: "Title",
labelStyle: TextStyle(color: Colors.white60),
fillColor: Colors.black,
filled: true,
),
),
SizedBox(height: 10),
TextFormField(
controller: dcontroller,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: "Description",
labelStyle: TextStyle(color: Colors.white60),
fillColor: Colors.black,
filled: true,
),
),
SizedBox(height: 10),
TextFormField(
controller: icontroller,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: "Image url",
labelStyle: TextStyle(color: Colors.white60),
fillColor: Colors.black,
filled: true,
),
),
SizedBox(height: 10),
Row(children: [
Text("Tags:", style:TextStyle(color: Colors.white)),
IconButton(onPressed: (){
var textEditingController = new TextEditingController(text: "tag");
textEditingControllers.add(textEditingController);
_addformWidget(textEditingController);
print(textformFields.length);
},
icon: Icon(Icons.add,color: Colors.white,),
)
],),
/*SingleChildScrollView(
child: new Column(
children: textformFields,
)
),*/
Expanded(
child: SizedBox(
height: 200.0,
child: ListView.builder(
itemCount: textformFields.length,
itemBuilder: (context,index) {
return textformFields[index];
}),
)
),
],
),
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: (){
List<String> test = [];
textEditingControllers.forEach((element) {
test.add(element.text);
});
if(tcontroller == '' && dcontroller == '' && icontroller == ''){
print("not valid");
}else{
var todo = Todo2(
title: tcontroller.text,
description: dcontroller.text,
image: icontroller.text,
tags: test,
);
updateData(todo, widget.docid.toString(),context);
setState(() {
showSnackBar(context, 'todo ${widget.doctitle} successfully updated!');
});
}
},
child: Icon(Icons.update),
),
);
}
}
You can't remove anything from the list with objects from tagForm(controller), because these objects are newly created and therefore not the same as in the list (as long as the == operator is not overwritten)
If you still want to have the widgets in a list instead of just storing the controllers and without having to change much, you could remove the widgets like this:
onPressed: (){
setState(() {
controller.dispose();
textEditingControllers.remove(controller);
textformFields.removeWhere((w) => w.controller = controller));
});
},
and change the type of your List: var textformFields = <TextFormField>[]; and of the method TextFormField tagForm(controller).
In general, you can of course optimize the state management, but with this solution it should work for now.
Dont't store Widget, it is bad way. Insteads store there property, render by List then remove by index when you need.
ps: some code syntax can wrong, i write this on browser.
class _TodoEditState extends State<TodoEdit> {
...
var textformFields = <String>[];
...
void _addformWidget([String? initValue]) {
setState(() => textformFields.add(initValue ?? ""));
}
...
Widget tagForm(String value, void Function(String) onChange, void Function() onRemove){
var openEditor = () {
// Open dialog with text field to edit from [value] call onChange with
// new value
OpenDialog().then((newvalue) {
if(newvalue != null) onChange(newvalue);
}
};
var delete = () {
// Open confirm dialog then remove
OpenConfirmDialog("your message").then((continue) {
if(continue) onRemove();
});
};
return InkWell(
onTap: openEditor,
child: Text(value), // render your tag value
);
}
...
#override
void initState() {
...
textformFields = List.filled(widget.doctags ?? 0, ""); // or List.generate/map if you want replace by own value.
}
...
#override
Widget build(BuildContext context) {
...
ListView.builder(
itemCount: textformFields.length,
itemBuilder: (context,index) => tagForm(
textformFields[index],
(newvalue) => setState(() => textformFields[index] = newvalue),
() => setState(() => textformFields = textformFields..removeAt(index));,
),
),
...
);
}
I have created a stateful customer information form and the there are two widgets that use the state - two list tiles with radio buttons and a drop down button. The list tiles respond to the code and updates their states and saves the data to the variable as expected.
But the drop down button only saves the value in the assigned variable, but does not display the new value instead of the hint.
I have followed sample code but as I'm new to Flutter I can't find where the mishap might be. Thank you for any help!
The code is as follows; please note that some of the label texts are in my native language and it wouldn't affect code readability. The code in question is in bold (**).
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class CustomerForm extends StatefulWidget {
const CustomerForm({Key key}) : super(key: key);
#override
CustomerFormState createState() {
return CustomerFormState();
}}
class CustomerFormState extends State<CustomerForm> {
final formKey = GlobalKey<FormState>();
String _name = '';
String _age = '';
String _nic = '';
String _sex = '';
String _telephone = '';
String _address = '';
String _email = '';
String _inquiry = '';
**String _branch = '';**
#override
Widget build(BuildContext context) => Scaffold(
resizeToAvoidBottomInset : false,
appBar: AppBar(
title: Text('ඔබේ තොරතුරු පහත පුරවන්න',
style: TextStyle(
fontSize: (20.0),),),
centerTitle: true,
backgroundColor: Colors.cyan,
shadowColor: Colors.tealAccent[50] ),
body:SingleChildScrollView(
child: Form(
key: formKey,
child: Column(children:[
Padding(
padding: const EdgeInsets.fromLTRB(10, 0, 10, 0),
child: TextFormField(
autofocus: true,
decoration: InputDecoration(labelText: 'නම'),
validator: (value) {
if (value.isEmpty) {
return 'මෙම තොරතුරු අවශ්යයි';}
else if(value.length < 4) {
return 'ඔබ යෙදූ නම කෙටි වැඩි ය.';}
return null;},
onSaved: (value) => _name = value),
),
Padding(
padding: const EdgeInsets.fromLTRB(10, 0, 10, 0),
child: TextFormField(
decoration: InputDecoration(labelText: 'වයස (අවු. 18ට වැඩි විය යුතුයි)'),
validator: (value) {
if (value.isEmpty) {
return 'මෙම තොරතුරු අවශ්යයි';}
else if (int.parse(value)<18) {
return 'වයස අවුරුදු 18ට වැඩි විය යුතුයි';}
else if (int.parse(value) > 99) {
return 'සැබෑ වයසක් ඇතුළත් කරන්න';}
else {
return null;}},
onSaved: (value) => _age = value),
),
Padding(
padding: const EdgeInsets.fromLTRB(10, 0, 10, 0),
child: TextFormField(
decoration: InputDecoration(
labelText: 'ජාතික හැඳුනුම්පත් අංකය'),
validator: (value) {
if (value.isEmpty) {
return 'මෙම තොරතුරු අවශ්යයි';}
//TODO finish regexp
String p = r'(^[0-9]v|V|x|X$)';
RegExp regExp = new RegExp(p);
if (regExp.hasMatch(p) && value.length == 10 ) {
return null;}
else
return 'ඇතුළත් කල ජාතික හැඳුනුම්පත් අංකය වලංගු නොවේ';},
onSaved: (value) => _nic = value),
),
Padding(
padding: const EdgeInsets.fromLTRB(10, 10, 10, 0),
child: Row(
children:[
SizedBox(
width: 100.0,
child: Text('ස්ත්රී / පුරුෂ භාවය :',
style: TextStyle(
color: Colors.black54,
fontSize: 16.0),),
),
Expanded(
child: ListTile(
leading:Radio<String>(
value:'male',
groupValue: _sex,
activeColor: Colors.teal,
onChanged: (value) {
setState(() {_sex = value;});},),
title: const Text('පුරුෂ'),),
),
Expanded(
child: ListTile(
leading:Radio<String>(
value:'female',
groupValue: _sex,
activeColor: Colors.teal,
onChanged: (value) {setState(() {_sex = value;});},),
title: const Text('ස්ත්රී'),),),
],
),
),
Padding(
padding: const EdgeInsets.fromLTRB(10, 0, 10, 0),
child: TextFormField(
decoration: InputDecoration(
labelText: 'දුරකථන අංකය'),
validator: (value) {
String pattern = r'^[0-9]{10}$';
RegExp regExp = new RegExp(pattern);
if (value.length == 0) {
return 'මෙම තොරතුරු අවශ්යයි';}
else if (!regExp.hasMatch(value)) {
return 'ඉලක්කම් 10ක් සහිත 0න් ආරම්භ වන වලංගු දුරකථන අංකයක් \n ඇතුළත් කරන්න';}
else {return null;}},
onSaved: (value) => _telephone = value),
),
Padding(
padding: const EdgeInsets.fromLTRB(10, 0, 10, 0),
child: TextFormField(
decoration: InputDecoration(
labelText: 'ලිපිනය'),
validator: (value) {
if (value.isEmpty) {
return 'මෙම තොරතුරු අවශ්යයි';}
else {return null;}},
onSaved: (value) => _address = value),
),
Padding(
padding: const EdgeInsets.fromLTRB(10, 0, 10, 0),
child: TextFormField(
decoration: InputDecoration(
labelText: 'විද්යුත් ලිපිනය (තිබේනම්)'),
keyboardType: TextInputType.emailAddress,
validator: (value) {
String p = "[a-zA-Z0-9\+\.\_\%\-\+]{1,256}" +
"\\#" + "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}" + "(" + "\\." +
"[a-zA-Z0-9][a-zA-Z0-9\\-]{0,25}" + ")+";
RegExp regExp = new RegExp(p);
if (value.isNotEmpty && !regExp.hasMatch(value)) {
return 'ඇතුළත් කල විද්යුත් ලිපිනය වලංගු නොවේ';}
else
return null;},
onSaved: (value) => _email = value)
),
Padding(
padding: const EdgeInsets.fromLTRB(10, 0, 10, 0),
child: TextFormField(
decoration: InputDecoration(
labelText: 'අමතර කරුණු / විමසීම්'),
onSaved: (value) => _inquiry = value),
),
Padding(padding: const EdgeInsets.fromLTRB(0, 0, 0, 25),),
**DropdownButton<String>(
hint:Text ('ඔබට ළඟම බැංකු ශාඛාව මෙතනින් තෝරන්න.'),
icon: Icon(Icons.arrow_downward),
iconSize: 24, elevation: 16, style: TextStyle(color: Colors.teal),
underline: Container(height: 2, color: Colors.teal,),
onChanged: (String value) {setState(() {_branch = value;});},
items: <String>['Matara', 'Colombo','Galle'].map<DropdownMenuItem<String>>((String value){
return DropdownMenuItem<String>(value:value,
child: Text(value, style: TextStyle(fontSize: 20.0), textAlign: TextAlign.center,));}).toList(),),**
Padding(padding: const EdgeInsets.fromLTRB(0, 0, 0, 45),),
ElevatedButton (
onPressed: () {
if (_sex.isEmpty){
final message = 'ස්ත්රි පුරුෂ බව ඇතුළත් කරන්න';
final snackBar = SnackBar(
content: Text(message),
backgroundColor:Colors.redAccent,
duration: Duration(milliseconds: 3000),);
ScaffoldMessenger.of(context).showSnackBar(snackBar);}
else
if (formKey.currentState.validate()){
formKey.currentState.save();
final message = '$_name, විමසීම සාර්ථකයි.';
final snackBar = SnackBar(
content: Text(message),
backgroundColor:Colors.blue,
duration: Duration(milliseconds: 3000),);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
return http.post(
Uri.parse('http://10.0.2.2:5000/api/userdata'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',},
body: jsonEncode(<String, String>{
'name': _name,
'age': _age,
'NIC': _nic,
'sex': _sex,
'tel': _telephone,
'addr': _address,
'email': _email,
'inquiry': _inquiry,
'branch': _branch
})
);
}},
child: Text('ඔබේ විමසීම මෙතැනින් අප වෙත යොමුකරන්න.'),
)
]
),
),
));}
I tried assigining _branch with 'value' of the button and reversing the names, it did not work. Then When I assigned _branch to the value attribute of teh drop down button it seemed to work but an error came on when the screen was reloaded
This might help you out:
DropdownButton(
hint: Text('ඔබට ළඟම බැංකු ශාඛාව මෙතනින් තෝරන්න.'),
icon: Icon(Icons.arrow_downward),
iconSize: 24,
value: _branch,
elevation: 16,
style: TextStyle(color: Colors.teal),
underline: Container(
height: 2,
color: Colors.teal,
),
onChanged: (value) async {
setState(() {
_branch = value;
debugPrint(value);
});
},
items: <String>['Matara', 'Colombo', 'Galle']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(
value,
style: TextStyle(fontSize: 20.0),
textAlign: TextAlign.center,
));
}).toList(),
),
You'vent declared the "value" inside the DropdownButton widget, if you want your text to appear soon as you choose an option from the Dropdown you must use it like this.
I guess if there's a problem after you change it maybe it's not related to dropdownbutton.
This could be very helpful
final List<String> _items = ['Matara', 'Colombo','Galle'];
late String _branch = _items[0]; //Default selected value
DropdownButton(
hint: Text('ඔබට ළඟම බැංකු ශාඛාව මෙතනින් තෝරන්න.'),
icon: Icon(Icons.arrow_downward),
iconSize: 24,
value: _branch,
elevation: 16,
style: TextStyle(color: Colors.teal),
underline: Container(
height: 2,
color: Colors.teal,
),
onChanged: (value) async {
setState(() {
_branch = value;
debugPrint(value);
});
},
items:_items.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(
value,
style: TextStyle(fontSize: 20.0),
textAlign: TextAlign.center,
)
);
}).toList(),
),
I'm working on flutter project .I have a revision form validator that is not working as expected. When I leave the TextFormField empty the validator doesn't show me anything. I want to stay on the revision form until I enter the values.
thanks in advance
my code :
class Revision extends StatefulWidget {
}
class _RevisionState extends State<Revision> with TickerProviderStateMixin {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
RevisionApi revisionApi = RevisionApi();
TextEditingController _Kilometrage_revisionController =
TextEditingController();
_showAddDialog() async {
await showDialog(
context: context,
builder: (context) => AlertDialog(
backgroundColor: Colors.white,
title: Text("Ajouter un évènement"),
content: StatefulBuilder(builder: (
BuildContext context,
StateSetter setState,
) {
return SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(children: [
Expanded(
child: DropdownButtonFormField(
decoration: InputDecoration(
hoverColor: Colors.white,
//contentPadding: EdgeInsets.only(left: 10, right: 15, top: 15),
labelText: 'Type',
alignLabelWithHint: true,
labelStyle: TextStyle(
color: kPrimaryColor,
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.grey),
),
),
dropdownColor: Colors.white,
value: status,
items: <DropdownMenuItem>[
DropdownMenuItem(
// value: 'videnge',
value: 0,
child: InkWell(
child: Text('videnge'),
hoverColor: Colors.indigo,
),
),
DropdownMenuItem(
// value: 'visite technique',
value: 1,
child: Text('visite technique'),
),
DropdownMenuItem(
// value: 'assurance véhicule',
value: 2,
child: Text('assurance véhicule'),
),
DropdownMenuItem(
// value: 'autre',
value: 3,
child: Text('autre'),
),
],
onChanged: (value) {
setState(() {
status = value;
});
},
)),
]),
if (status == 1) visiTechniqueDropdown(),
]),
));
}),
actions: <Widget>[
TextButton(
child: Text(
"Enregistrer",
style: TextStyle(
color: Colors.red, fontWeight: FontWeight.bold),
),
onPressed: () {
if (status == null) return;
setState(() {
if (_events[_controller.selectedDay] != null) {
_events[_controller.selectedDay].add(status);
} else {
_events[_controller.selectedDay] = [status];
}
prefs.setString(
"events", json.encode(encodeMap(_events)));
status;
setRevision();
_KilometrageController.clear();
_eventController.clear();
_EmplacementController.clear();
_DateController.clear();
_repeat_revisionController.clear();
_revision_agenceController.clear();
_Kilometrage_revisionController.clear();
Navigator.of(context).pop();
// Navigator.pop(context);
});
},
),
new TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('Retour'),
),
],
));
}
void setRevision() async {
print("hello");
if (_formKey.currentState.validate()) {
String kilometrage_pour_vidange = _KilometrageController.text;
String revision_type = status.toString();
String revision_title = _eventController.text;
String revision_location = _EmplacementController.text;
String revision_date = _DateController.text;
String repeat_revision = _repeat_revisionController.text;
String revision_agence = _revision_agenceController.text;
String kilometrage_revision = _Kilometrage_revisionController.text;
revisionApi
.setRevision(
revision_type,
revision_title,
revision_date,
revision_location,
kilometrage_pour_vidange,
repeat_revision,
revision_agence,
kilometrage_revision,
)
.then((data) {
if (data != null) {
Navigator.pop(context);
Navigator.of(context).pop();
Navigator.push(
context, MaterialPageRoute(builder: (context) => Revision()));
}
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text(data)));
}).catchError((error) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text(error.toString())));
});
setState(() {});
}
}
Widget visiTechniqueDropdown() {
return Column(mainAxisSize: MainAxisSize.min, children: [
Row(
children: [
Flexible(
child: TextFormField(
onFieldSubmitted: (_) => FocusScope.of(context).nextFocus(),
validator: (value) {
if (value.isEmpty) {
return 'Password is required';
}
return null;
},
controller: _DateController,
cursorColor: kPrimaryColor,
decoration: InputDecoration(
labelText: 'Date',
alignLabelWithHint: true,
labelStyle: TextStyle(
color: kPrimaryColor,
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.grey),
How i can set the validator correctly ?
This is for you. Thanks and enjoy
// Create a corresponding State class.
// This class holds data related to the form.
class MyFormState extends State<MyForm> {
// Create a global key that uniquely identifies the Form widget
// and allows validation of the form.
//
// Note: This is a GlobalKey<FormState>,
// not a GlobalKey<MyFormState>.
final _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
// Build a Form widget using the _formKey created above.
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextFormField(
// The validator receives the text that the user has entered.
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter some text';
}
return null;
},
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: ElevatedButton(
onPressed: () {
// Validate returns true if the form is valid, or false otherwise.
if (_formKey.currentState!.validate()) {
// If the form is valid, display a snackbar. In the real world,
// you'd often call a server or save the information in a database.
// sendData();
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Processing Data')));
}
},
child: Text('Submit'),
),
),
],
),
);
}
}
I am trying to build a new widget every time a button is pressed.
I am using object of Global key to change the current state of Form as other local keys doesn't provide me the capability to change the state of FormBuilder
final _formKey = GlobalKey<FormBuilderState>();
Problem is when I try to create object of GlobalKey(_formKey) under listTile widget that I 'm trying to build on runtime, form builderr text fields don't work i.e appear and disappear instantly! But when create _formKey oustside the listTile widget under stateful widget, many other errors appears
i.e setState() called after dispose(), Global key used for multiple widgets etc.
Should I use here local keys i.e value,object or unique key? But they aren't providing me to change the current state of form builder!
Check my code:
class _addMenuState extends State<addMenu> {
var _price = TextEditingController();
var _itemName = TextEditingController();
var _desc = TextEditingController();
File _image;
String itemImageUrl;
List<menu> items = [];
final _formKey = GlobalKey<FormBuilderState>();
Future getImageFromGallery() async {
var image = await ImagePicker.pickImage(source: ImageSource.gallery);
setState(() {
_image = image;
print('Image Path $_image');
});
}
Future getImageFromCamera() async {
var image = await ImagePicker.pickImage(source: ImageSource.camera);
setState(() {
_image = image;
print('Image Path $_image');
});
}
Future uploadItemOfShop(BuildContext context) async {
FirebaseStorage storage = FirebaseStorage.instance;
Reference ref = storage.ref().child("${this.widget.rr.name}'s ${_itemName.text} Price ${_price.text}" + DateTime.now().toString());
if(_image.toString()==''){
Flushbar(
title: "Menu Item Image is empty",
message: "Please Add some Image first",
backgroundColor: Colors.red,
boxShadows: [BoxShadow(color: Colors.red[800], offset: Offset(0.0, 2.0), blurRadius: 3.0,)],
duration: Duration(seconds: 3),
)..show(context);
}else{
UploadTask uploadTask = ref.putFile(_image);
uploadTask.then((res) async {
itemImageUrl = await res.ref.getDownloadURL();
});
}
/* setState(() {
print("Logo uploaded");
Scaffold.of(context).showSnackBar(SnackBar(
content: Text('Your Restaurnat Logo has Uploaded'),
duration: Duration(seconds: 3),
));
});*/
}
Widget Divido() {
return Divider(
thickness: 5,
color: Colors.black45,
height: 2,
);
}
Widget listTile(int i) {
final _formKey = GlobalKey<FormBuilderState>();
return SingleChildScrollView(
child: ListTile(
title: //Code not needed here for this question as I haven't used key in it
subtitle: FormBuilder(
key: _formKey,
child: Column(
children: [
FormBuilderTextField(
controller: _itemName,
keyboardType: TextInputType.text,
name: 'item_name',
decoration: InputDecoration(labelText: 'Enter Item name'),
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(context),
]),
),
FormBuilderTextField(
controller: _price,
name: 'price',
keyboardType: TextInputType.number,
decoration: InputDecoration(labelText: 'Enter Price'),
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(context),
]),
),
FormBuilderTextField(
maxLength: 150,
controller: _desc,
keyboardType: TextInputType.multiline,
maxLines: null,
name: 'desc',
decoration: InputDecoration(
labelText: 'Description',
),
validator: FormBuilderValidators.compose(
[
FormBuilderValidators.required(context),
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
RaisedButton(
child: Text(
"Save",
style: TextStyle(color: Colors.white, fontSize: 16),
),
color: Colors.red,
onPressed: () {
debugPrint("null");
menu item = menu(
_itemName.text, _price.text, _desc.text, itemImageUrl);
items.add(item);
setState(() {
_count = _count + 1;
});
},
),
RaisedButton(
child: Text(
"Reset",
style: TextStyle(color: Colors.white, fontSize: 16),
),
color: Colors.grey,
onPressed: () {
_formKey.currentState.reset();
},
)
],
),
Divido()
],
),
),
selectedTileColor: Colors.red.shade300,
),
);
}
int _count = 1;
bool _showAnotherWidget = false;
#override
Widget build(BuildContext context) {
List<Widget> children = List.generate(_count, (int i) => listTile(i));
return Scaffold(
appBar: AppBar(
title: Text("Add Menu for ${this.widget.rr.name} Shop"),
),
body: SingleChildScrollView(
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: children
),
),
)
);
}
}