Flutter Dropdown with sqllite - flutter

Good noon every one i want to ask on how to put a dropdown onchanged i am using sqllite for my database.
edit_note_page.dart
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
actions: [buildButton()],
),
body: Form(
key: _formKey,
child: NoteFormWidget(
category: category,
onChangedCategory: (category) => setState(() => this.category = category),
),
),
);
note_form_widget.dart
Widget buildCategory() => DropdownButton(
icon: const Icon(Icons.keyboard_arrow_down),
items: <String>['A1', 'A2', 'A3', 'A4','A5','C1']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: category,
child: Text(value),
);
}).toList(), onChanged: (String? value)
{
setState(() {
dropdownValue = newValue!;//im getting an error on this part
});
},
Logs
error encounter
The method 'setState' isn't defined for the type 'NoteFormWidget'.
Try correcting the name to the name of an existing method, or defining a method named 'setState'.
[{
"resource": "/c:/Users/VIMS-SERVER/Documents/Flutter Projects/apps/lib/widget/note_form_widget.dart",
"owner": "_generated_diagnostic_collection_name_#0",
"code": {
"value": "undefined_identifier",
"target": {
"$mid": 1,
"external": "https://dart.dev/diagnostics/undefined_identifier",
"path": "/diagnostics/undefined_identifier",
"scheme": "https",
"authority": "dart.dev"
}
},
"severity": 8,
"message": "Undefined name 'dropdownValue'.\nTry correcting the name to one that is defined, or defining the name.",
"source": "dart",
"startLineNumber": 229,
"startColumn": 11,
"endLineNumber": 229,
"endColumn": 24
}]
[{
"resource": "/c:/Users/VIMS-SERVER/Documents/Flutter Projects/apps/lib/widget/note_form_widget.dart",
"owner": "_generated_diagnostic_collection_name_#0",
"code": {
"value": "undefined_identifier",
"target": {
"$mid": 1,
"external": "https://dart.dev/diagnostics/undefined_identifier",
"path": "/diagnostics/undefined_identifier",
"scheme": "https",
"authority": "dart.dev"
}
},
"message": "Undefined name 'newValue'.\nTry correcting the name to one that is defined, or defining the name.",
}]

The setState method doesn't work on StatelessWidget because StatelessWidget doesn't have a state. Only StatefulWidget has a state, and therefore only it has a setState.
So you most turn your StatelessWidget to StatefulWidget.

I think your note_widget is stateless so you change to the stateful widget. you cant use a set state callback on the stateless widget.Dartpad live check here.you can use another state management tool(Provider ,cubit,riverport,bloc) to update your value
DropdownButton(
icon: const Icon(Icons.keyboard_arrow_down),
items: <String>['A1', 'A2', 'A3', 'A4', 'A5', 'C1']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
value: dropdownvalu,
onChanged: (values) {
setState(() {
dropdownvalu = values.toString();
});
},
)
Widget
class _ParentState extends State<Parent> {
Widget build(context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
IconButton(
onPressed: () {
setState(() {
counter++;
});
},
icon: const Icon(Icons.add),
),
],
),
body: Column(
children: [
DropdownButton(
icon: const Icon(Icons.keyboard_arrow_down),
items: <String>['A1', 'A2', 'A3', 'A4', 'A5', 'C1']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
value: dropdownvalu,
onChanged: (values) {
setState(() {
dropdownvalu = values.toString();
});
},
),
Center(
child: Text(
"$dropdownvalu",
style: TextStyle(fontSize: 30),
)),
],
),
);
}
}
SampleCode
import 'package:flutter/material.dart';
//import 'package:pucon/home.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Parent(),
);
}
}
class Parent extends StatefulWidget {
#override
State<Parent> createState() => _ParentState();
}
String dropdownvalu = "A1";
class _ParentState extends State<Parent> {
Widget build(context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
IconButton(
onPressed: () {
setState(() {
counter++;
});
},
icon: const Icon(Icons.add),
),
],
),
body: Column(
children: [
DropdownButton(
icon: const Icon(Icons.keyboard_arrow_down),
items: <String>['A1', 'A2', 'A3', 'A4', 'A5', 'C1']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
value: dropdownvalu,
onChanged: (values) {
setState(() {
dropdownvalu = values.toString();
});
},
),
Center(
child: Text(
"$dropdownvalu",
style: TextStyle(fontSize: 30),
)),
],
),
);
}
}
int counter = 0;
class Child extends StatefulWidget {
Child({Key? key}) : super(key: key);
#override
_ChildState createState() => _ChildState();
}
class _ChildState extends State<Child> {
#override
Widget build(BuildContext context) {
return Center(
child: Text(
"$dropdownvalu",
style: TextStyle(fontSize: 30),
));
} //to be incremented when the parent's button is clicked on.
}

// dbHelper
Future<List> getEmployeeData() async {
try {
final dbClient = await db;
var l = await dbClient!.transaction(
(txn) async => txn.rawQuery("SELECT * FROM ${DbConstants.tblGloEmployeeMaster} where is_active = 1"),
);
return l;
} catch (e) {
return [];
}
}
// getx
// login controller
// init
final employeeModelList = List<EmployeeModel>.empty(growable: true).obs;
// create method
void _getEmployees() async {
List list = await _dbHelper.getEmployeeData();
employeeModelList.value = [];
employeeModelList.value = list.map((employeeModel) => EmployeeModel.fromJson(employeeModel)).toList();
}
// create model
class EmployeeModel {
EmployeeModel({
required this.employeeId,
required this.employeeNm,
});
late final int employeeId;
late final String employeeNm;
EmployeeModel.fromJson(Map<String, dynamic> json) {
employeeId = json['employee_id'];
employeeNm = json['employee_nm'];
}
Map<String, dynamic> toJson() {
final _data = <String, dynamic>{};
_data['employee_id'] = employeeId;
_data['employee_nm'] = employeeNm;
return _data;
}
}
// stateless widget
// call
Container(
child: _searchEmployee(context),
),
// method
Widget _searchEmployee(BuildContext context) {
return Obx(
() => CustomSearchableDropDown(
items: _loginController.employeeModelList,
label: Strings.selectEmployee,
labelStyle: Theme.of(context).textTheme.bodyText1!.merge(TextStyles.defaultRegular),
dropdownLabelStyle: Theme.of(context).textTheme.bodyText1!.merge(TextStyles.defaultRegular),
dropDownMenuItems: _loginController.employeeModelList.map((item) {
return "${item.employeeId} - ${item.employeeNm}"; // ui view
}).toList(),
suffixIcon:
Icon(Icons.arrow_drop_down, size: Sizes.s16, color: Get.isDarkMode ? AppColors.white : AppColors.black),
decoration: BoxDecoration(border: Border(bottom: BorderSide(color: AppColors.fontGray))),
onChanged: (value) {
if (value != null) {
EmployeeModel employeeModel = value;
_loginController.employeeId.value = int.parse(employeeModel.employeeId);
_loginController.employeeName.value = employeeModel.employeeNm;
}
},
),
);
}

Related

Flutter: A value of type 'GameNameEnum' can't be assigned to a variable of type 'GameNameEnum'

I am getting a really strange error in my code. When I try to use _dialogPlatform = newValue; or _dialogGameName = newValue; I get a red highlight by VS code saying I cannot assign a value with some type to a variable of the same type.
Complete error: A value of type 'Platform' can't be assigned to a variable of type 'Platform'.
Try changing the type of the variable, or casting the right-hand type to 'Platform'.
Please help.
import 'package:all_gta_cheats/enums/enums.dart';
import 'package:all_gta_cheats/widgets/drop_down_menu.dart';
import 'package:flutter/material.dart';
class FilterDialogBox extends StatefulWidget {
const FilterDialogBox({
Key? key,
required this.initialPlatformValue,
required this.initialGameNameValue,
required this.initialIsFavValue,
required this.onApply,
}) : super(key: key);
final Platform initialPlatformValue;
final GameNameEnum initialGameNameValue;
final bool initialIsFavValue;
final Function(
Platform platform,
GameNameEnum gameNameEnum,
bool isFav,
) onApply;
#override
_FilterDialogBoxState createState() => _FilterDialogBoxState();
}
class _FilterDialogBoxState extends State<FilterDialogBox> {
final TextStyle actionsTextStyle = TextStyle(fontSize: 18);
late GameNameEnum _dialogGameName;
late Platform _dialogPlatform;
late bool _dialogIsFav;
#override
void initState() {
super.initState();
_dialogGameName = widget.initialGameNameValue;
_dialogPlatform = widget.initialPlatformValue;
_dialogIsFav = widget.initialIsFavValue;
}
#override
Widget build(BuildContext context) {
return AlertDialog(
title: Text('Search Filter'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
DropDownMenu<Platform>(
initialValue: _dialogPlatform,
itemsList: Platform.values,
onChanged: <Platform>(newValue) {
//Platform value changes here
_dialogPlatform = newValue;
print(newValue.toString());
},
),
DropDownMenu<GameNameEnum>(
initialValue: _dialogGameName,
itemsList: GameNameEnum.values,
onChanged: <GameNameEnum>(newValue) {
//GameName value changes here
_dialogGameName = newValue;
print(newValue.toString());
},
),
SwitchListTile(
title: const Text('Show only favourites'),
value: _dialogIsFav,
onChanged: (bool value) {
setState(() {
_dialogIsFav = value;
print(_dialogIsFav);
//widget.dialogIsFav = value;
});
},
secondary: const Icon(Icons.favorite),
),
],
),
),
actions: <Widget>[
TextButton(
child: Text(
'Cancel',
style: actionsTextStyle,
),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: Text(
'Apply',
style: actionsTextStyle,
),
onPressed: () {
widget.onApply(_dialogPlatform, _dialogGameName, _dialogIsFav);
Navigator.of(context).pop();
},
),
],
);
}
}

in flutter I can not change value from dropdown button

below the StatefulWidget class Customdropdownbutton where I defined the dropdown button
class Customdropdownbutton extends StatefulWidget {
Customdropdownbutton({#required this.defaultValue, #required this.listValue, this.enable});
String defaultValue;
List<String> listValue;
bool enable;
#override
_CustomdropdownbuttonState createState() => _CustomdropdownbuttonState();
}
class _CustomdropdownbuttonState extends State<Customdropdownbutton> {
#override
Widget build(BuildContext context) {
String _valore;
return DropdownButton<String>(
value: widget.defaultValue.isEmpty ? widget.listValue[0] : _valore,
icon: const Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
style: const TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: widget.enable ? (String newValue) {
setState(() {
_valore = newValue;
});
} : null,
items: widget.listValue.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
);
}
}
below I try to instantiate the class Customdropdownbutton and in UI I see the dropdown button but I can not change the value (the text selected is alwais the widget.listValue[0])
class MyMain extends StatefulWidget {
#override
Widget build(BuildContext context) {
final auth = Provider.of<AuthBase>(context, listen: false);
final String emailMy = auth.currentUser.email;
return scaffold(
.....
body: _buildFormChildren(emailMy),
}
List<Widget> _buildFormChildren(String emailMy) {
List<String> listValue = ['1a', '2b'];
String defaultValue = '1a';
bool enable = true;
return [
**Customdropdownbutton(defaultValue: '', listValue : listValue, enable: true, ),**
],
....
}
}
In the build method of your _CustomdropdownbuttonState, you check if widget.defaultValue is empty (which always is since you're not changing it) and it evaluates widget.listValue[0]. Even if you change _valore, the condition will keep checking if widget.defaultValue is empty. You can do the following:
class _CustomdropdownbuttonState extends State<Customdropdownbutton> {
// Use _valore as a property instead of a local variable
String _valore;
#override
void initState() {
super.initState();
// Use _valore to store the default value
_valore = widget.defaultValue;
}
#override
Widget build(BuildContext context) {
return DropdownButton<String>(
// Check _valore instead of widget.defaultValue
value: _valore.isEmpty ? widget.listValue[0] : _valore,
icon: const Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
style: const TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: widget.enable ? (String newValue) {
setState(() {
_valore = newValue;
});
} : null,
items: widget.listValue.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
);
}
}

Corresponding DropDownButtonFormFields in Flutter

I'm implementing corresponding dropdowns (where the options of the second dropdown depend on the first like so) that uses a list of objects in this format:
List<State> states = [
new State(stateId: 1, stateName: "New York", cities: [
new City(cityId: 1, cityName: "New York City"),
new City(cityId: 2, cityName: "Buffalo") ...
And the widget code is like so:
children: <Widget>[
DropdownButtonFormField<int>(
decoration: InputDecoration(labelText: 'State'),
value: selectedStateId,
items: states.map((State state) {
return new DropdownMenuItem<int>(
value: state.stateId,
child: new Text(states.singleWhere((x) => x.stateId == state.stateId).stateName),
);
}).toList(),
onChanged: (int newStateId) {
setState(() {
this.selectedCityId = states.singleWhere((x) => x.stateId == newStateId).cities[0].cityId; // set to first city for this state
this.selectedStateId = = newStateId;
});
},
),
DropdownButtonFormField<int>(
decoration: InputDecoration(labelText: 'City'),
value: selectedCityId,
items: states.singleWhere((x) => x.stateId == selectedStateId)
.cities
.map((City city) {
return new DropdownMenuItem<int>(
value: city.cityId,
child: new Text(states
.singleWhere((x) => x.stateId == selectedStateId).cities.singleWhere((x) => x.cityId == city.cityId).cityName),
);
}).toList(),
onChanged: (int newCityId) {
setState(() {
this.selectedCityId = newCityId;
});
},
)
],
When I change the State dropdown in this example, I get an error:
"There should be exactly one item with [DropdownButton]'s value: 1.
Either zero or 2 or more [DropdownMenuItem]s were detected with the same value".
The "1" in the above error corresponds to whatever the selected city value was prior to changing the state, so I know that the error relates to the fact that it's still looking for the old selectedCityId and it is no longer in the item list, but I'm not sure why as I've changed that value in setState. A key to this issue, I believe, is the same exact code works if I just change the DropDownButtonFormField to regular DropDownButtons, but I'd like to use the built in label text that comes along with the former.
Edit
You can use key: UniqueKey() int City DropdownButtonFormField
DropdownButtonFormField<int>(
key: UniqueKey(),
decoration: InputDecoration(labelText: 'City'),
You can copy paste run full code below
You can set selectedStateId and selectedCityId to states's attribute
You can not directly set to a value like selectedStateId = 1, because system will compare address
code snippet
int selectedStateId;
int selectedCityId;
#override
void initState() {
selectedStateId = states[0].stateId;
selectedCityId = states[0].cities[0].cityId;
super.initState();
}
working demo
full code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class City {
int cityId;
String cityName;
City({this.cityId, this.cityName});
}
class CountryState {
int stateId;
String stateName;
List<City> cities;
CountryState({this.stateId, this.stateName, this.cities});
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
List<CountryState> states = [
CountryState(stateId: 1, stateName: " York", cities: [
City(cityId: 1, cityName: "York City"),
City(cityId: 2, cityName: "Buffalo")
]),
CountryState(stateId: 2, stateName: "A", cities: [
City(cityId: 3, cityName: "A1"),
City(cityId: 4, cityName: "A2")
])
];
int selectedStateId;
int selectedCityId;
#override
void initState() {
selectedStateId = states[0].stateId;
selectedCityId = states[0].cities[0].cityId;
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
DropdownButtonFormField<int>(
decoration: InputDecoration(labelText: 'State'),
value: selectedStateId,
items: states.map((CountryState state) {
return DropdownMenuItem<int>(
value: state.stateId,
child: Text(states
.singleWhere((x) => x.stateId == state.stateId)
.stateName),
);
}).toList(),
onChanged: (int StateId) {
setState(() {
this.selectedCityId = states
.singleWhere((x) => x.stateId == StateId)
.cities[0]
.cityId; // set to first city for this state
this.selectedStateId = StateId;
});
},
),
DropdownButtonFormField<int>(
key: UniqueKey(),
decoration: InputDecoration(labelText: 'City'),
value: selectedCityId,
items: states
.singleWhere((x) => x.stateId == selectedStateId)
.cities
.map((City city) {
return DropdownMenuItem<int>(
value: city.cityId,
child: Text(states
.singleWhere((x) => x.stateId == selectedStateId)
.cities
.singleWhere((x) => x.cityId == city.cityId)
.cityName),
);
}).toList(),
onChanged: (int CityId) {
setState(() {
this.selectedCityId = CityId;
});
},
)
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
I posted this example on the Flutter issues board and they could not duplicate on the latest stable version (1.20.2 as of this comment). I upgraded my flutter version (I was on 1.17.1) and the same code ran without issue, so for anyone experiencing the same issue I suggest updating your flutter version.

Save DropdownButtons and TextField selected Data into a List

I'm trying to create an AlertDialog that will receive a Future-List or a List of the data from the Dropdownbuttons and the TextField that are inside of these Alert. In my App when I call these function for the AlertDialog, there will be 3 DropdownButtons and 1 TextField so the User can select the info that he wants, and then when he presses "OK" from the AlerDialog, the data he selected will be inside of the list, so I can use it with Firestore.
This is my AlertDialog:
Future<List> createAlertDialog(BuildContext context){
return showDialog(context: context, builder: (ctx){
return AlertDialog(
title: Text('Text'),
content: Column(
children: [
DropdownButton(
value: iconNameSelected,
items: iconlistdrop,
hint: Text('Select Icon'),
onChanged: (value) {
iconNameSelected = value;
setState(() {});
},
),
DropdownButton(
value: activelabelSelected,
items: activelistdrop,
hint: Text('Select Active label'),
onChanged: (value1) {
activelabelSelected = value1;
setState(() {});
},
),
DropdownButton(
value: inactivelabelSelected,
items: inactivelistdrop,
hint: Text('Select InActive label'),
onChanged: (value2) {
inactivelabelSelected = value2;
setState(() {});
},
),
TextField(
),
],
),
actions: <Widget>[
MaterialButton(
elevation: 5.0,
child: Text("OK"),
onPressed: (){
final values = [];
Navigator.of(ctx).pop(values);
},
)
],
);
});
}
Here's how I attempted to call it inside my InkWell widget:
createAlertDialog(context).then((value){
printf(value[0]);
printf(value[1]);
printf(value[2]);
printf(value[3]);
}
Here's some extra stuff from the Data I have inserted inside the DropdownButtons:
List<DropdownMenuItem<String>> iconlistdrop = [];
List<DropdownMenuItem<String>> activelistdrop = [];
List<DropdownMenuItem<String>> inactivelistdrop = [];
String iconNameSelected = null;
String activelabelSelected = null;
String inactivelabelSelected = null;
void loadIcon () {
iconlistdrop = [];
iconlistdrop.add(DropdownMenuItem(
child: Text('LightBulb'),
value: 'lightbulbOutline',
));
iconlistdrop.add(DropdownMenuItem(
child: Text('Lock'),
value: 'lock',
));
iconlistdrop.add(DropdownMenuItem(
child: Text('Check'),
value: 'check',
));
}
void activelbl () {
activelistdrop = [];
activelistdrop.add(DropdownMenuItem(
child: Text('On'),
value: 'On',
));
activelistdrop.add(DropdownMenuItem(
child: Text('Locked'),
value: 'Locked',
));
}
void inactivelbl () {
inactivelistdrop = [];
inactivelistdrop.add(DropdownMenuItem(
child: Text('Off'),
value: 'Off',
));
inactivelistdrop.add(DropdownMenuItem(
child: Text('Locked'),
value: 'Unlocked',
));
}
loadIcon();
activelbl();
inactivelbl();
My Class:
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
var temperature;
var humidity;
Future getWeather() async {
http.Response response = await
http.get('http://api.openweathermap.org/data/2.5/weather?
q=Curitiba&units=metric&appid=8c1ce29a0b974e97562564d892cd5a97');
var results = jsonDecode(response.body);
setState(() {
this.temperature = results['main']['temp'];
this.humidity = results['main']['humidity'];
});
}
#override
void initState () {
this.getWeather();
super.initState();
}
#override
Widget build(BuildContext context) {
final AuthService _auth = AuthService();
final user = Provider.of<User>(context);
Future getSubCollection(){
return Firestore.instance.collection('dadosusuarios').document(user.uid).collection('buttons').getDocuments();
}
I would use a map for the values and separate the dialog to another widget and give it a constructor in case you might want it to have initial values.
import 'package:flutter/material.dart';
class MyAlertDialog extends StatefulWidget {
final Map<String, dynamic> initialValues;
const MyAlertDialog({
Key key,
this.initialValues,
}) : super(key: key);
#override
_MyAlertDialogState createState() => _MyAlertDialogState();
}
class _MyAlertDialogState extends State<MyAlertDialog> {
Map<String, dynamic> _values;
TextEditingController _controller;
#override
initState() {
super.initState();
_values = widget.initialValues ??
{'input1': 'One', 'input2': 'Two', 'input3': 'Free', 'input4': 'Four'};
_controller = TextEditingController(text: _values['input4']);
}
#override
Widget build(BuildContext context) {
return AlertDialog(
title: Text('Text'),
content: Column(
children: [
DropdownButton(
value: _values['input1'],
items: <String>['One', 'Two', 'Free', 'Four']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
hint: Text('Select Icon'),
onChanged: (value1) {
setState(() {
_values['input1'] = value1;
});
},
),
DropdownButton(
value: _values['input2'],
items: <String>['One', 'Two', 'Free', 'Four']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
hint: Text('Select Active label'),
onChanged: (value2) {
setState(() {
_values['input2'] = value2;
});
},
),
DropdownButton(
value: _values['input3'],
items: <String>['One', 'Two', 'Free', 'Four']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
hint: Text('Select InActive label'),
onChanged: (value3) {
setState(() {
_values['input3'] = value3;
});
},
),
TextField(
controller: _controller,
),
],
),
actions: <Widget>[
MaterialButton(
elevation: 5.0,
child: Text("OK"),
onPressed: () {
_values['input4'] = _controller.text.trim();
Navigator.of(context).pop(_values);
},
)
],
);
}
}
Here i look if there is a value passed from the constructor. If not put some defaults. Update the map with each user input change and finally once the dialog popped return the map. Using map here is better in my opinion and would make pushing the values to Firestore easier.
var result = await showDialog(
context: context,
builder: (ctx) {
return MyAlertDialog(initialValues: /* Your default values if exist*/ );
});
print(result);

Minlines or similar in TextField Flutter

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class Todo {
String title;
String description;
Todo(this.title, this.description);
}
class TextEditingControllerWorkaroud extends TextEditingController {
TextEditingControllerWorkaroud({String text}) : super(text: text);
void setTextAndPosition(String newText, int caretPosition) {
int offset = caretPosition != null ? caretPosition : newText.length;
value = value.copyWith(
text: newText,
selection: TextSelection.collapsed(offset: offset),
composing: TextRange.empty);
}
}
void main() {
runApp(MaterialApp(
title: 'Passing Data',
home: TodosScreen(
todos: List.generate(
20,
(i) => Todo(
'Todo $i',
'A description of what needs to be done for Todo $i',
),
),
),
));
}
class TodosScreen extends StatelessWidget {
final List<Todo> todos;
TodosScreen({Key key, #required this.todos}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Todos'),
),
body: ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(todos[index].title),
onTap: () async {
Map results = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailScreen1(todo: todos[index]),
),
);
if (results["new"]!=results["old"] || results["newTitle"]!=results["oldTitle"]){
todos[index].description = results["new"];
todos[index].title = results["oldTitle"];
final snackBar = SnackBar(duration: Duration(milliseconds: 2000),
content: Text('Todo Saved Succesfully'),
action: SnackBarAction(
label: 'Undo',
onPressed: () {
print("go back to old");
todos[index].description = results["old"];
todos[index].title = results["oldTitle"];
},
),
);
// Find the Scaffold in the Widget tree and use it to show a SnackBar!
Scaffold.of(context).hideCurrentSnackBar();
Scaffold.of(context).showSnackBar(snackBar);
}
},
);
},
),
);
}
}
class DetailScreen1 extends StatefulWidget {
final Todo todo;
DetailScreen1({Key key, #required this.todo}) : super(key: key);
#override
DetailScreen1State createState() => DetailScreen1State();
}
class DetailScreen1State extends State<DetailScreen1> {
var descriptionTextContent = "";
var titleTextContent = "";
#override
void initState() {
super.initState();
print("intialized");
descriptionTextContent = widget.todo.description;
titleTextContent = widget.todo.title;
}
#override
Widget build(BuildContext context) {
TextEditingControllerWorkaroud descriptionEditWidgetController =
TextEditingControllerWorkaroud(text: descriptionTextContent);
TextEditingControllerWorkaroud titleEditWidgetController =
TextEditingControllerWorkaroud(text: titleTextContent);
TextField descriptionEditWidget = new TextField(
maxLines: 4,
keyboardType: TextInputType.multiline,
controller: descriptionEditWidgetController,
onChanged: (value) {
handleCurrentText(value, descriptionEditWidgetController);
},
);
TextField titleEditWidget = new TextField(
maxLines: 1,
keyboardType: TextInputType.text,
controller: titleEditWidgetController,
onChanged: (value) {
handleCurrentTitle(value, titleEditWidgetController);
},
);
descriptionEditWidgetController.setTextAndPosition(
descriptionTextContent, descriptionTextContent.length);
titleEditWidgetController.setTextAndPosition(
titleTextContent, titleTextContent.length);
return WillPopScope(
child: Scaffold(
appBar: AppBar(
title: Text(widget.todo.title),
leading: new IconButton(
icon: new Icon(Icons.arrow_back),
onPressed: () {
SystemChannels.textInput.invokeMethod('TextInput.hide');
Navigator.pop(context, {
'new': descriptionTextContent,
"old": widget.todo.description,
"newTitle": titleTextContent,
"oldTitle": widget.todo.title,
},
);
},
),
),
body: Padding(
padding: EdgeInsets.all(16.0), child: Column(children: <Widget>[titleEditWidget, descriptionEditWidget],)),
),
onWillPop: () {
Navigator.pop(context, {
'new': descriptionTextContent,
"old": widget.todo.description,
"newTitle": titleTextContent,
"oldTitle": widget.todo.title,
},
);
},
);
}
handleCurrentText(String value,
TextEditingControllerWorkaroud descriptionEditWidgetController) {
setState(() {
descriptionTextContent = value;
print("value is " + value);
});
}
void handleCurrentTitle(String value, TextEditingControllerWorkaroud titleEditWidgetController) {
setState(() {
titleTextContent = value;
});
}
}
The code above is properly functioning code that can be run directly. I have the problem that is TextField has property maxlines. If its null then it auto adjust as the text size grows/shrinks. And if we set it to constant as soon as we increase textContent it acts like scrollable in the widget. But what I want is something called "minLines" that is We start with default no of lines(like if we set max lines to constant) and then we can adjust the size of TextField if text grows(like if we set max lines to null). Also when the text content is beyond the range under the screen it becomes scrollable.
I would have handled that easily if I would be allowed to change maxLines attribute at runtime. I would have simply set a listener on textChange and managed the limits. But its final so I can edit that as well. What can I do?
In recent versions of Flutter, there is actually minLines parameter of TextField and it acts as you described.
First of all the very first mistake that I think was that there was no use of changing state continuously as the user enters the text.My work around was to change state only when I want maxlines to edit
So I set maxlines to a variable defined in the class and that variable I modify as soon as I wanted it (when text exceeds the no of characters)
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class Todo {
String title;
String description;
Todo(this.title, this.description);
}
class TextEditingControllerWorkaroud extends TextEditingController {
TextEditingControllerWorkaroud({String text}) : super(text: text);
void setTextAndPosition(String newText, int caretPosition) {
int offset = caretPosition != null ? caretPosition : newText.length;
value = value.copyWith(
text: newText,
selection: TextSelection.collapsed(offset: offset),
composing: TextRange.empty);
}
}
void main() {
runApp(MaterialApp(
title: 'Passing Data',
home: TodoScreen(
todos: List.generate(
5,
(i) => Todo(
'Todo $i',
'A description of what needs to be done for Todo $i',
),
),
),
));
}
class TodoScreenState extends State<TodoScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Todos'),
),
floatingActionButton: new FloatingActionButton(
onPressed: () async {
setState(() {
print("pressed");
Todo newTodo = Todo("todo", "");
widget.todos.insert(widget.todos.length, newTodo);
});
int index = widget.todos.length - 1;
Map results = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailScreen1(todo: widget.todos[index]),
),
);
if (results["new"] != results["old"] ||
results["newTitle"] != results["oldTitle"]) {
widget.todos[index].description = results["new"];
widget.todos[index].title = results["newTitle"];
final snackBar = SnackBar(
duration: Duration(milliseconds: 2000),
content: Text('Todo Saved Succesfully'),
action: SnackBarAction(
label: 'Undo',
onPressed: () {
setState(() {
widget.todos[index].description = results["old"];
widget.todos[index].title = results["oldTitle"];
});
},
),
);
// Find the Scaffold in the Widget tree and use it to show a SnackBar!
Scaffold.of(context).hideCurrentSnackBar();
Scaffold.of(context).showSnackBar(snackBar);
}
},
child: Icon(Icons.add),
),
body: ListView.builder(
itemCount: widget.todos.length,
itemBuilder: (context, index) {
return Dismissible(
background: Container(color: Colors.green[700]),
key: Key(widget.todos[index].title),
onDismissed: (direction) {
print(direction);
Todo currentTodo = widget.todos[index];
setState(() {
widget.todos.removeAt(index);
});
final snackBar = SnackBar(
duration: Duration(milliseconds: 2000),
content: Text('Todo Deleted Succesfully'),
action: SnackBarAction(
label: 'Undo',
onPressed: () async {
setState(() {
widget.todos.insert(index, currentTodo);
});
},
),
);
// Find the Scaffold in the Widget tree and use it to show a SnackBar!
Scaffold.of(context).hideCurrentSnackBar();
Scaffold.of(context).showSnackBar(snackBar);
},
child: ListTile(
title: Text(widget.todos[index].title),
onTap: () async {
Map results = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
DetailScreen1(todo: widget.todos[index]),
),
);
if (results["new"] != results["old"] ||
results["newTitle"] != results["oldTitle"]) {
widget.todos[index].description = results["new"];
widget.todos[index].title = results["newTitle"];
final snackBar = SnackBar(
duration: Duration(milliseconds: 2000),
content: Text('Todo Saved Succesfully'),
action: SnackBarAction(
label: 'Undo',
onPressed: () {
setState(() {
widget.todos[index].description = results["old"];
widget.todos[index].title = results["oldTitle"];
});
},
),
);
// Find the Scaffold in the Widget tree and use it to show a SnackBar!
Scaffold.of(context).hideCurrentSnackBar();
Scaffold.of(context).showSnackBar(snackBar);
}
},
),
);
},
),
);
}
}
class TodoScreen extends StatefulWidget {
final List<Todo> todos;
TodoScreen({Key key, #required this.todos}) : super(key: key);
#override
TodoScreenState createState() => TodoScreenState();
}
class DetailScreen1 extends StatefulWidget {
final Todo todo;
DetailScreen1({Key key, #required this.todo}) : super(key: key);
#override
DetailScreen1State createState() => DetailScreen1State();
}
class DetailScreen1State extends State<DetailScreen1> {
var descriptionTextContent = "";
var titleTextContent = "";
var size = 3;
var currentSize="fixed";
#override
void initState() {
super.initState();
print("intialized");
descriptionTextContent = widget.todo.description;
titleTextContent = widget.todo.title;
if (descriptionTextContent.length>=100){
size=null;
currentSize="variable";
}
}
#override
Widget build(BuildContext context) {
TextEditingControllerWorkaroud descriptionEditWidgetController =
TextEditingControllerWorkaroud(text: descriptionTextContent);
TextEditingControllerWorkaroud titleEditWidgetController =
TextEditingControllerWorkaroud(text: titleTextContent);
TextField descriptionEditWidget = new TextField(
decoration: new InputDecoration(hintText: 'Description'),
maxLines: size,
keyboardType: TextInputType.multiline,
controller: descriptionEditWidgetController,
onChanged: (value) {
handleCurrentText(value, descriptionEditWidgetController);
},
);
TextField titleEditWidget = new TextField(
decoration: new InputDecoration(hintText: 'Title'),
maxLines: 1,
keyboardType: TextInputType.text,
controller: titleEditWidgetController,
onChanged: (value) {
handleCurrentTitle(value, titleEditWidgetController);
},
);
descriptionEditWidgetController.setTextAndPosition(
descriptionTextContent, descriptionTextContent.length);
titleEditWidgetController.setTextAndPosition(
titleTextContent, titleTextContent.length);
return WillPopScope(
child: Scaffold(
appBar: AppBar(
title: Text(widget.todo.title),
leading: new IconButton(
icon: new Icon(Icons.arrow_back),
onPressed: () {
SystemChannels.textInput.invokeMethod('TextInput.hide');
Navigator.pop(
context,
{
'new': descriptionTextContent,
"old": widget.todo.description,
"newTitle": titleTextContent,
"oldTitle": widget.todo.title,
},
);
},
),
),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
children: <Widget>[titleEditWidget, descriptionEditWidget],
)),
),
onWillPop: () {
Navigator.pop(
context,
{
'new': descriptionTextContent,
"old": widget.todo.description,
"newTitle": titleTextContent,
"oldTitle": widget.todo.title,
},
);
},
);
}
handleCurrentText(String value,
TextEditingControllerWorkaroud descriptionEditWidgetController) {
descriptionTextContent = value;
if (descriptionTextContent.length>100 && currentSize=="fixed"){
setState(() {
print("called");
size = null;
currentSize="variable";
});
}
else if (descriptionTextContent.length<=100&&currentSize=="variable")
{
setState(() {
print("called");
size = 3;
currentSize="fixed";
});
}
}
void handleCurrentTitle(
String value, TextEditingControllerWorkaroud titleEditWidgetController) {
titleTextContent = value;
}
}
The function to note is handleTextChange of descripionTextField