drop down menu - example - ¿Cómo implementar la lista desplegable en flutter?
listbox flutter (10)
Tengo una lista de ubicaciones que deseo implementar como una lista desplegable en Flutter. Soy bastante nuevo en el idioma. Esto es lo que he hecho.
new DropdownButton(
value: _selectedLocation,
onChanged: (String newValue) {
setState(() {
_selectedLocation = newValue;
});
},
items: _locations.map((String location) {
return new DropdownMenuItem<String>(
child: new Text(location),
);
}).toList(),
Esta es mi lista de artículos:
List<String> _locations = [''A'', ''B'', ''C'', ''D''];
Y estoy recibiendo el siguiente error.
Another exception was thrown: ''package:flutter/src/material/dropdown.dart'': Failed assertion: line 468 pos 15: ''value == null || items.where((DropdownMenuItem<T> item) => item.value == value).length == 1'': is not true.
Asumo que el valor de _selectedLocation
está poniendo nulo. Pero lo estoy inicializando así.
String _selectedLocation = ''Please choose a location'';
Cuando me topé con este problema de querer un DropdownStringButton menos genérico, acabo de crearlo:
dropdown_string_button.dart
import ''package:flutter/material.dart'';
// Subclass of DropdownButton based on String only values.
// Yes, I know Flutter discourages subclassing, but this seems to be
// a reasonable exception where a commonly used specialization can be
// made more easily usable.
//
// Usage:
// DropdownStringButton(items: [''A'', ''B'', ''C''], value: ''A'', onChanged: (string) {})
//
class DropdownStringButton extends DropdownButton<String> {
DropdownStringButton({
Key key, @required List<String> items, value, hint, disabledHint,
@required onChanged, elevation = 8, style, iconSize = 24.0, isDense = false,
isExpanded = false, }) :
assert(items == null || value == null || items.where((String item) => item == value).length == 1),
super(
key: key,
items: items.map((String item) {
return DropdownMenuItem<String>(child: Text(item), value: item);
}).toList(),
value: value, hint: hint, disabledHint: disabledHint, onChanged: onChanged,
elevation: elevation, style: style, iconSize: iconSize, isDense: isDense,
isExpanded: isExpanded,
);
}
El error que está recibiendo debe solicitar una propiedad de un objeto nulo. Su artículo debe ser nulo, de modo que cuando solicite que se compare su valor, está obteniendo ese error. Compruebe que está obteniendo datos o que su lista es una lista de objetos y no cadenas simples.
En primer lugar, investiguemos lo que dice el error (he citado el error que se produjo con Flutter 1.2, pero la idea es la misma):
Afirmación fallida: línea 560 pos 15: ''elementos == nulo || items.isEmpty || valor == nulo || items.where ((DropdownMenuItem item) => item.value == value) .length == 1 '': no es cierto.
Hay cuatro or
condiciones. Al menos uno de ellos debe cumplirse:
- Se proporcionaron elementos (una lista de widgets de
DropdownMenuItem
). Esto eliminaitems == null
. - Se proporcionó una lista no vacía. Esto elimina
items.isEmpty
. - También se dio un valor (
_selectedLocation
). Esto elimina elvalue == null
. Tenga en cuenta que este es el valor deDropdownMenuItem
, no el valor deDropdownMenuItem
.
Por lo tanto, sólo queda la última comprobación. Se reduce a algo como:
Iterar a través de
DropdownMenuItem
''s. Encuentra todos los que tienen unvalue
que es igual a_selectedLocation
. Luego, verifique cuántos elementos coinciden fueron encontrados. Debe haber exactamente un widget que tenga este valor. De lo contrario, lanzar un error.
La forma en que se presenta el código, no hay un widget DropdownMenuItem
que tenga un valor de _selectedLocation
. En su lugar, todos los widgets tienen su valor establecido en null
. Desde null != _selectedLocation
, la última condición falla. Verifique esto estableciendo _selectedLocation
en null
: la aplicación debería ejecutarse.
Para solucionar el problema, primero debemos establecer un valor en cada DropdownMenuItem
(para que algo pueda pasarse a la onChanged
llamada onChanged
):
return DropdownMenuItem(
child: new Text(location),
value: location,
);
La aplicación seguirá fallando. Esto se debe a que su lista aún no contiene el valor de _selectedLocation
. Puedes hacer que la aplicación funcione de dos maneras:
- Opción 1 . Agregue otro widget que tenga el valor (para satisfacer
items.where((DropdownMenuItem<T> item) => item.value == value).length == 1
). Podría ser útil si desea permitir que el usuario vuelva a seleccionar.Please choose a location
opción dePlease choose a location
. - Opción 2 . Pase algo para
hint:
paremter y establezcaselectedLocation
ennull
(para satisfacer elvalue == null
condiciónvalue == null
). Útil si no desea.Please choose a location
para seguir siendo una opción.
Vea el siguiente código que muestra cómo hacerlo:
import ''package:flutter/material.dart'';
void main() {
runApp(Example());
}
class Example extends StatefulWidget {
@override
State<StatefulWidget> createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
// List<String> _locations = [''Please choose a location'', ''A'', ''B'', ''C'', ''D'']; // Option 1
// String _selectedLocation = ''Please choose a location''; // Option 1
List<String> _locations = [''A'', ''B'', ''C'', ''D'']; // Option 2
String _selectedLocation; // Option 2
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: DropdownButton(
hint: Text(''Please choose a location''), // Not necessary for Option 1
value: _selectedLocation,
onChanged: (newValue) {
setState(() {
_selectedLocation = newValue;
});
},
items: _locations.map((location) {
return DropdownMenuItem(
child: new Text(location),
value: location,
);
}).toList(),
),
),
),
);
}
}
Me enfrentaba a un problema similar con DropDownButton cuando intentaba mostrar una lista dinámica de cadenas en el menú desplegable. Terminé creando un plugin: flutter_search_panel . No es un complemento desplegable, pero puede mostrar los elementos con la función de búsqueda.
Usa el siguiente código para usar el widget:
FlutterSearchPanel(
padding: EdgeInsets.all(10.0),
selected: ''a'',
title: ''Demo Search Page'',
data: [''This'', ''is'', ''a'', ''test'', ''array''],
icon: new Icon(Icons.label, color: Colors.black),
color: Colors.white,
textStyle: new TextStyle(color: Colors.black, fontWeight: FontWeight.bold, fontSize: 20.0, decorationStyle: TextDecorationStyle.dotted),
onChanged: (value) {
print(value);
},
),
Necesitas agregar value: location
en tu código para trabajarlo. Mira this
items: _locations.map((String location) {
return new DropdownMenuItem<String>(
child: new Text(location),
value: location,
);
}).toList(),
Prueba esto
new DropdownButton<String>(
items: <String>[''A'', ''B'', ''C'', ''D''].map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
onChanged: (_) {},
)
Puede usar la clase DropDownButton
para crear una lista desplegable:
...
...
String dropdownValue = ''One'';
...
...
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: DropdownButton<String>(
value: dropdownValue,
onChanged: (String newValue) {
setState(() {
dropdownValue = newValue;
});
},
items: <String>[''One'', ''Two'', ''Free'', ''Four'']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
),
);
...
...
Por favor, consulte esta página web de aleteo
Tienes que tener esto en cuenta (de los documentos de DropdownButton):
"Los elementos deben tener valores distintos y si el valor no es nulo, debe estar entre ellos".
Así que básicamente tienes esta lista de cuerdas.
List<String> _locations = [''A'', ''B'', ''C'', ''D''];
Y su valor en la propiedad de valor desplegable se inicializa así:
String _selectedLocation = ''Please choose a location'';
Solo intente con esta lista:
List<String> _locations = [''Please choose a location'', ''A'', ''B'', ''C'', ''D''];
Eso debería funcionar :)
También puedes ver la propiedad "hint" si no quieres agregar una cadena como esa (fuera del contexto de la lista), podrías ir con algo como esto:
DropdownButton<int>(
items: locations.map((String val) {
return new DropdownMenuItem<String>(
value: val,
child: new Text(val),
);
}).toList(),
hint: Text("Please choose a location"),
onChanged: (newVal) {
_selectedLocation = newVal;
this.setState(() {});
});
coloque el valor dentro de los ítems. Entonces funcionará,
new DropdownButton<String>(
items:_dropitems.map((String val){
return DropdownMenuItem<String>(
value: val,
child: new Text(val),
);
}).toList(),
hint:Text(_SelectdType),
onChanged:(String val){
_SelectdType= val;
setState(() {});
})
Digamos que estamos creando una lista desplegable de divisas:
List _currency = ["INR", "USD", "SGD", "EUR", "PND"];
List<DropdownMenuItem<String>> _dropDownMenuCurrencyItems;
String _currentCurrency;
List<DropdownMenuItem<String>> getDropDownMenuCurrencyItems() {
List<DropdownMenuItem<String>> items = new List();
for (String currency in _currency) {
items.add(
new DropdownMenuItem(value: currency, child: new Text(currency)));
}
return items;
}
void changedDropDownItem(String selectedCurrency) {
setState(() {
_currentCurrency = selectedCurrency;
});
}
Agregue el siguiente código en la parte del cuerpo:
new Row(children: <Widget>[
new Text("Currency: "),
new Container(
padding: new EdgeInsets.all(16.0),
),
new DropdownButton(
value: _currentCurrency,
items: _dropDownMenuCurrencyItems,
onChanged: changedDropDownItem,
)
])