Вопрос или проблема
Я использую DropDownMenu в Flutter, чтобы искать товары в своем ProductList. Как только я ввожу что-то, что не соответствует значению товара в списке, я получаю следующую ошибку: RangeError (length): Неверное значение: Действительный диапазон значений пустой: 0
Вот код, который я пробовал:
products.when(
data: (productList) {
var filteredList = searchController.text.isNotEmpty ? productList
.where((e) => e.name.contains(RegExp(
searchController.text,
caseSensitive: false)))
.toList()
: productList.take(5).toList();
return SizedBox(
child: DropdownMenu<String?>(
textStyle: TextStyle(color: Colors.black),
inputDecorationTheme: InputDecorationTheme(
hintStyle: TextStyle(color: Colors.black),
helperStyle: TextStyle(color: Colors.black),
labelStyle: TextStyle(color: Colors.black),
),
controller: searchController,
width: 350,
hintText: "Поиск товара...",
requestFocusOnTap: true,
enableFilter: true,
enabled: selectedProduct == null,
label: const Text('Выберите товар'),
onSelected: (String? selectedProductName) {
setState(() {
selectedProduct = selectedProductName;
});
},
dropdownMenuEntries: filteredList.isEmpty
? [
DropdownMenuEntry<String?>(
value: '',
label: 'Результаты не найдены.',
)
]
: filteredList.map<DropdownMenuEntry<String?>>(
(ProductModel product) {
return DropdownMenuEntry<String?>(
value: product.id.toString(),
label:
'${product.name} (${product.location})',
);
}).toList(),
),
);
},
error: (_, __) => getLoadError(_),
loading: () => getLoadIndicator(),
),
Мой productList загружается нормально.
ИЗМЕНЕНИЕ: Эта ошибка возникает только если отфильтрованный список изначально был заполнен поиском. Если я ищу что-то, чего нет изначально, эта ошибка не появляется. Например, если в списке есть [Яблоки, Апельсины], и я ищу “OA”, я получаю ошибку, но если я ищу “Zzz”, мне возвращается пустой список.
Это известная проблема в фреймворке. https://github.com/flutter/flutter/issues/154532
Она должна быть исправлена в следующем стабильном релизе.
Есть обходной путь с использованием searchCallback.
searchCallback: (entries, query) {
if (query.isEmpty) {
return null;
}
final int index = entries.indexWhere(
(entry) => entry.label.toLowerCase().contains(query),
);
return index != -1 ? index : null;
},
Ответ или решение
Решение проблемы с Flutter DropDownMenu: Ошибка RangeError (length)
Введение
Использование виджета DropDownMenu
в Flutter может иногда приводить к непредвиденным ошибкам, особенно при работе с динамически загружаемыми данными и фильтрацией по введенным значениям. В данной статье мы разберем ошибку RangeError (length): Invalid value: Valid value range is empty: 0
, которая возникает в процессе работы с DropDownMenu
и предоставим решения для её устранения.
Описание проблемы
Согласно вашему коду, ошибка возникает, когда пользователь вводит запрос в текстовое поле и этот запрос не совпадает с ни одним элементом из вашего списка продуктов. В частности, если вы осуществляете фильтрацию и результат оказывается пустым, то DropdownMenu
не может правильно обработать это состояние, что и приводит к ошибке.
Вы отметили, что ошибка появляется в тех случаях, когда сначала происходила фильтрация по непустому списку, а затем запрос не возвращает ни одного совпадения.
Пример вашего кода
Вот ваш код с несколькими комментариями для понимания:
products.when(
data: (productList) {
var filteredList = searchController.text.isNotEmpty
? productList.where((e) => e.name.contains(RegExp(
searchController.text,
caseSensitive: false)))
.toList()
: productList.take(5).toList();
return SizedBox(
child: DropdownMenu<String?>(
textStyle: TextStyle(color: Colors.black),
inputDecorationTheme: InputDecorationTheme(
hintStyle: TextStyle(color: Colors.black),
helperStyle: TextStyle(color: Colors.black),
labelStyle: TextStyle(color: Colors.black),
),
controller: searchController,
width: 350,
hintText: "Search for a product...",
requestFocusOnTap: true,
enableFilter: true,
enabled: selectedProduct == null,
label: const Text('Select A Product'),
onSelected: (String? selectedProductName) {
setState(() {
selectedProduct = selectedProductName;
});
},
dropdownMenuEntries: filteredList.isEmpty
? [
DropdownMenuEntry<String?>(
value: '',
label: 'No results found.',
)
]
: filteredList.map<DropdownMenuEntry<String?>>(
(ProductModel product) {
return DropdownMenuEntry<String?>(
value: product.id.toString(),
label: '${product.name} (${product.location})',
);
}).toList(),
),
);
},
error: (_, __) => getLoadError(_),
loading: () => getLoadIndicator(),
);
Анализ проблемы
Причиной ошибки является то, что DropdownMenu
ожидает список элементов, и когда он оказывается пустым, это приводит к сбоям в логике обработки. Когда вы сначала вводите "OA", и у вас есть продукты, например, "Apples" и "Oranges", то при отсутствии совпадений возникает неясность для DropdownMenu
, так как он не знает, как работать с пустым списком.
Решение
Согласно вашим наблюдениям, ошибка не возникает, если вы изначально ищете несуществующий продукт, например, "Zzz". Итак, правильным подходом будет реализация обработчика поиска.
Вот как можно доработать ваш код:
searchCallback: (entries, query) {
if (query.isEmpty) {
return null; // Возвращаем null для обработки пустого запроса
}
final int index = entries.indexWhere(
(entry) => entry.label.toLowerCase().contains(query.toLowerCase()),
);
return index != -1 ? index : null; // Возвращаем индекс или null
}
Заключение
Проблема с RangeError (length): Invalid value: Valid value range is empty: 0
в DropdownMenu
может быть решена с помощью правильной обработки состояния пустого результата. Использование searchCallback
позволяет контролировать логику поиска и избежать конфликтов при работе с пустыми списками.
Некоторые ошибки в Flutter могут быть временными, как указано в комментариях к известным проблемам, так что стоит следить за обновлениями фреймворка. Ваша реализация с использованием обработчика поиска является надежным способом обойти существующие проблемы и улучшить пользовательский интерфейс вашего приложения на Flutter.
Рекомендации
- Всегда проверяйте ваши запросы на пустоту.
- Используйте обработчики, которые могут контролировать индексы и состояния.
- Обратитесь к официальной документации и форумы для уточнения информации о текущих статусах ошибок в самом фреймворке.
Этот подход поможет избежать ошибок и обеспечит более плавный и интуитивно понятный пользовательский интерфейс для ваших пользователей.