Is there a way to always display the hint in a DropDownButton? - flutter

For example, in a TextField it is possible to set an InputDecoration with a label text, that shows in the center of the TextField when there is no user input, and then shows above the user's input text afterward.
With a DropDownButton I can only seem to get the hint text to display before the user makes a selection, and then it disappears and only displays the user's selection. Is there a way to mimic the TextField's behavior?
Thanks!

You can achieve that using DropDownButtonFormField widget instead of DropDownButton. DropDownButtonFormField has decoration property which lets you use labelText which goes over the top of the field after selecting an item from the list. Sample working code below:
return DropdownButtonFormField<String>(
decoration: InputDecoration(
labelText: 'select option'
),
value: selected,
items: ["A", "B", "C"]
.map((label) => DropdownMenuItem(
child: Text(label),
value: label,
))
.toList(),
onChanged: (value) {
setState(() => selected = value);
},
);
Output:
Hope this answers your question.

Related

How do i modify the data of an existing variable in flutter?

I want to make an editable TextWidget in flutter but I don't really know how to go around it, I did some research, but still can't find a good solution.
Here's my sample code below.
I have a variable called
int qty = 1;
and so I called the variable in TextWidget
Column(
children: [
Text(
"${qty}",
style: TextStyle(),
)
],
),
I want to have these features that make user tab on the value to change it if they want, upon tap, a pop-up dialog will show to give the user the ability to change the existing value to whatever the user wants.
Please if anyone knows how, please help.
You will need a statfull widget to call setState and make the UI update with the new value stored in your qty variable. (I'am assuming that you are not using any state managment).
I wrote a possible solution for what you need.
Let look into some considerations:
Text will show whatever is in the qty as long we call setState after (or do it inside) we change the value of qty.
You need some widget to detect your tap. If you want to the text be 'clicable' then it should be wraped inside that widget.
The onTap/onPress call back of that widget should show a new widget. For this you can use the already made showDialog() and pass it a Dialog Widget. in here you will put your ui for that.
In some point of that UI you need to introduce the new value. So you can use a simple TextField that will save the introduced value, where you can assign it to qty, without forgetting to call setState! Note that it deal with strings, so you neet to do an int.parse() ou double.parse accordingly to you qty var type.
And I think that's it.
The could be other ways of doing it. This is a good and simple approach for your need.
I wrote a piece of code to help or somelse how is trying to do it:
InkWell(
// can be gesture detector, button, etc
onTap: () => showDialog(
context: context,
builder: (context) => Dialog(
child: Container(
color:
Colors.white60, // change it accordingly to you
height: 80, // change it accordingly to you
width: 200, // change it accordingly to you
child: Column(
children: [
const Text('Change your value here'),
TextField(
decoration:
InputDecoration(hintText: qty.toString()),
onChanged: (insertValue) => setState(() {
qty = int.parse(insertValue);
}),
// you can use other callBack function (like onComplete,
// onSaved), wich is more eficient than calling setState eveytime,
// but you have to do the needed adtaptions. Like onSave
// needs a key to call the save function. is easy just google it.
),
],
)),
)),
child: Text(
"${qty}",
),
),
What you are probably looking is a DropdownButton.
You would have something like this:
int qty = 1;
List<int> listOfValues = [1,2,3,4];
and then in your column you would have
DropdownButton<int>(
// This are the list of items that will appear in your dropdown menu.
// items is all the options you want your users to be able to select from,
// and it take a list of `DropdownMenuItem`. So instead of creating a `DropdownMenuItem`
// for each of the items in `listOfValues`, we iterate through it and return
// a `DropdownMenuItem`
items: listOfValues
.map((item) => DropdownMenuItem<int>(
value: item,
child: Text('$item'),
))
.toList(),
value: qty,
onChanged: (value) {
if (value != null) {
setState(() {
qty = value;
});
}
},
),
For more information on DropDownButton, check the following links:
https://api.flutter.dev/flutter/material/DropdownButton-class.html
https://www.youtube.com/watch?v=K8Y7sWZ7Q3s
Note: In a scenario where you want to increase the quantity of an item, like in a shopping cart, maybe having a button increment qty by 1 would be better.

is there any way to control dropdown items based on another dropdown's value? [flutter]

I have stateless class contains form with 4 tabs and one of those tabs contains 3 dropdowns to select address on for country and based on value selected I want the second dropdown (which is for cities) to view its items.
all items for dropdowns comes from local sqlite database.
the problem is the second dropdown dose not view its items but when I use debugger I found the list comes from database successfully but the update of list value on stateless class not happen.
any way to solve this??
DropdownButtonFormField<Region>(
decoration: InputDecoration(
isDense: true,
floatingLabelBehavior:
FloatingLabelBehavior.auto,
labelStyle: TextStyle(fontSize: 22),
contentPadding:
EdgeInsets.symmetric(vertical: 9),
),
value: regionList.isEmpty
? region
: helRegion.getReg(
user.regionAdresse, regionList),
//icon: Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
onChanged: (selectedRegion) {
onRegionSelected(context, user,
region, province, provinceList, selectedRegion);
},
items: regionList
.map((project) => DropdownMenuItem(
child: Text(project.Name),
value: project,
))
here is onRegionSelected function:
onRegionSelected(BuildContext context, User user, Region region, Province province, List<Province> provinceList, Region selectedRegion) async {try { showLoadingDialog(context);
final _provinceList = await getProvinceList(selectedRegion.id);
region = selectedRegion;
user.regionAdresse = selectedRegion.id;
province = null;
//provinceList.clear();
provinceList = _provinceList;
Navigator.pop(context);} catch (e) {
//TODO: handle error
rethrow; }}
First of all, you should use a stateful class so that when you select the first dropdown, the information that will appear in the second one is updated, and so on.
If your idea is to keep the format stateless, you could also save the responses from the DB in a stream and wrap the dropdowns in streamBuiler, so they could be updated when the new data pointed to by each dropdown is updated.
I'm leaving this as an answer since I don't have the reputation to add it as a comment.

How make default selection in FormBuilderDropdown list in flutter?

I am having a multiple FormBuilder dropdown in my flutter app. all of them are dependent dropdown.
i want to implement something like this:
the first of the main parent dropdown value should be auto fill and hence all other are filled or selected depending on the parents selection.
I can see the text filled in all the dropdown but as it is the dependent it is disabled for first dropdown to be clicked once.
How to fix this issue?
in the below screenshot we can see that the data is filled or been selected in every dropdown but second dropdown is still been disabled. it only gets enabled after clicking or selecting the value in first dropdown. enter image description here
Here is my code for first dropdown
padding: const EdgeInsets.all(12.0),
child: FormBuilderDropdown(
name: 'City',
decoration: InputDecoration(
labelText: 'City',
),
allowClear: true,
hint: Text(widget.callLocationModel.CityName),
initialValue: citySelected,
validator: FormBuilderValidators.compose(
[FormBuilderValidators.required(context)]),
items: cityList
.map((citySelected) => DropdownMenuItem(
value: cityChoosen,
child:new Text('$citySelected'),
))
.toList(),
onChanged: (String value){
setState(() {
citySelected= value;
//this fuction calls my second dropdown depending on first dropdown value selection
fetchSite(citySelected);
});
},
),
),
I assume all this layout is done in a stageful widget, which has a variable in it’s state for each selected value (when it’s selected). You may override initState member function and set the initial values there, so when the widget is built for the first time it will have those values preselected.

Is there a way for the showTimePicker() in Flutter to not reset any value in TextInputField?

I implemented a page in my Flutter application that has a text input field and 2 time pickers that are activated by pressing the button to make them appear. The issue is that if I have a new value in the TextInputField and use one of the time pickers, after I'm done what I have typed in the input field will just reset.
Code snippet from the input field:
SizedBox(
width: 350,
child: TextField(
controller: titleController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
hintText: 'Title',
),
onChanged: (value) {
title = value;
},
),
),
I've tried keeping the value of what is being typed in through a titleController and I have also attempted using the onChanged() method and a separate variable to keep the value in there. These solutions both didn't work for me, however. Is there any other solution to this issue?
If your TextField inside a stateless widget it will keep clearing the value of the controller everytime something pop on the screen, so try to put your TextField inside a stateful widget

Flutter textfield behaves strange (updating with the wrong value)

I ran into a weird behavior related to the TextFormField, so I maintained a list of Objects in the parent widget, I'm using the following code to render a list of child widgets
children: <Widget>[
...childProfiles
.map((e) => ChildProfileCard(
childProfile: e,
removeChildProfile: removeChildProfile))
.toList(),
And the ChildProfileCard includes a TextFormField, the code is like the following
TextFormField(
decoration: const InputDecoration(
contentPadding: EdgeInsets.only(top: 0),
hintText: "Enter child's name",
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Name is required';
}
return null;
},
),
There is a "remove" function that simply removes one of the items from the list like the following
setState(() {
childProfiles = childProfiles
.where((childProfile) => childProfile.id != childProfileToRemove.id)
.toList();
});
When there are more than two items (two child widgets), I input some texts in the TextFormField in the first child widgets, then I remove the first item, the text will always automatically apply to the second child widget, what did I do wrong? I can confirm the list is correctly updated, but the text behaves strangely.
Before deleting, you can see we have different texts for different widgets
After deleting, the first widget's text is wrongfully copied over to the next widget, you can see the uuid is the second widget's.
You should Use any unique key while building ChildProfileCard
ChildProfileCard(key: Key(<ANY UNIQUE VALUE>),)
Example
ChildProfileCard(key: Key(e.id),)