tl;dr With filtering on, I get out-of-bounds errors in my DropdownMenu and I can't figure out why.
I'm learning Flutter. My DropdownMenu crashes with RangeError Index out of range
if I select anything other than the first entry in the drop down AND enableFilter: true,
is set. It does not do this with enableFilter: false
.
Things I've tried:
LevelOfBadness
enum.Can someone help me understand either:
--or--
import 'dart:developer';
import 'package:flutter/material.dart';
class PageFive extends StatefulWidget
{
const PageFive({super.key});
@override
State<StatefulWidget> createState()
{
return PageFiveState();
}
}
enum Villian { Gargamil, Doofenschmirtz, Kinderlumper }
enum LevelOfBadness {I, II, III, IV, V, X}
class PageFiveState extends State
{
Villian? theBiggestVillian;
LevelOfBadness? selectedBadnessRating;
TextEditingController tfc = TextEditingController();
@override
Widget build(BuildContext context)
{
return MaterialApp(
home: SafeArea(
child: Scaffold(
backgroundColor: Colors.amber[200] ,
appBar: AppBar(
centerTitle: true,
title: const Text("This is light red"),
backgroundColor: Colors.red[300]),
body:
Container(
margin: const EdgeInsets.all(15.0),
padding: const EdgeInsets.all(3.0),
decoration: BoxDecoration(border: Border.all(color: Colors.blueAccent)),
child: Row (
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Flexible(
child: Container(
margin: const EdgeInsets.all(15.0),
padding: const EdgeInsets.all(3.0),
decoration: BoxDecoration(border: Border.all(color: Colors.redAccent)),
child: SizedBox(
child: Column(
children: [
const Text("Choose a Villian"),
RadioListTile<Villian> (
tileColor: Colors.blue,
title: Text(Villian.Gargamil.name),
groupValue: theBiggestVillian,
value: Villian.Gargamil,
onChanged: (Villian? newValue) {
setState(() {
theBiggestVillian = newValue;
});
},
),
RadioListTile<Villian> (
tileColor: Colors.green,
title: Text(Villian.Doofenschmirtz.name),
groupValue: theBiggestVillian,
value: Villian.Doofenschmirtz,
onChanged: (Villian? newValue) {
setState(() {
theBiggestVillian = newValue;
});
},
),
RadioListTile<Villian> (
tileColor: Colors.orange,
title: Text(Villian.Kinderlumper.name),
groupValue: theBiggestVillian,
value: Villian.Kinderlumper,
onChanged: (Villian? newValue) {
setState(() {
theBiggestVillian = newValue;
log(theBiggestVillian.toString());
});
},
),
const Spacer(),
const Text("Select a Badness Rating"),
DropdownMenu(
// enableFilter: true, // If I turn this on, I get out of bounds exceptions whenever I select anything but the first entry. Why?
onSelected: (currentBadnessSelectedInDropdownMenu) {
if (currentBadnessSelectedInDropdownMenu !=null)
{
setState(()
{
log("Type is: " + currentBadnessSelectedInDropdownMenu.runtimeType.toString());
log("Value is: " + currentBadnessSelectedInDropdownMenu.toString());
selectedBadnessRating = currentBadnessSelectedInDropdownMenu;
});
}
},
dropdownMenuEntries: const <DropdownMenuEntry<LevelOfBadness>>[
DropdownMenuEntry(value: LevelOfBadness.I, label: "Underwhelming"),
DropdownMenuEntry(value: LevelOfBadness.II, label: "Rookie"),
DropdownMenuEntry(value: LevelOfBadness.III, label: "Moderate"),
DropdownMenuEntry(value: LevelOfBadness.IV, label: "Fully-Operational"),
DropdownMenuEntry(value: LevelOfBadness.V, label: "Level 5 Baddie"),
DropdownMenuEntry(value: LevelOfBadness.X, label: "Mega-baddie!"),
],
),
const Spacer(),
const Text("Type a Characteristic"),
TextField(
controller: tfc,
onChanged: textFieldChangedCallback,
decoration: const InputDecoration(
border: OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(12))),
hintText: 'Write something here',
),
),
const Spacer(),
],
),
),
),
),
Container(
margin: const EdgeInsets.all(15.0),
padding: const EdgeInsets.all(3.0),
decoration: BoxDecoration(border: Border.all(color: Colors.greenAccent)),
child: SizedBox(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Spacer(),
const Padding(padding: EdgeInsets.all(10)),
SizedBox(
width: 150,
child: Text("Our villian, ${theBiggestVillian?.name??""}, is of calibre $selectedBadnessRating. Most folks would describe them as ${tfc.value.text}. In conclusion, don't be a villian."),
),
const Spacer(),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(onPressed: onPressedSubmit, child: const Text("Submit")),
// Spacer(), // if I put a Spacer() here, I get unbounded size! Grr.
ElevatedButton(onPressed: onPressedReset, child: const Text("Reset")),
],
),
const Spacer(),
],
),
),
),
],
),
),
),
),
);
}
void onPressedSubmit()
{
setState(() {
// todo
});
}
void onPressedReset()
{
setState(() {
tfc.text = "";
theBiggestVillian = null;
// selectedBadnessRating = null; // This doesn't do what I want yet either. I want to be able to deselect the item....
log("Reset ran");
});
}
void textFieldChangedCallback(String newValue)
{
setState(() {});
}
}
You need to provide filtercallback
when enabledFilter:true
child: DropdownMenu<LevelOfBadness>(
enableFilter: true,
filterCallback: (entries, filter) {
return entries;
},