Flutter DropDownMenu (RangeError (length): Неверное значение: Действительный диапазон значений пуст: 0)

Вопрос или проблема

Я использую 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.

Рекомендации

  • Всегда проверяйте ваши запросы на пустоту.
  • Используйте обработчики, которые могут контролировать индексы и состояния.
  • Обратитесь к официальной документации и форумы для уточнения информации о текущих статусах ошибок в самом фреймворке.

Этот подход поможет избежать ошибок и обеспечит более плавный и интуитивно понятный пользовательский интерфейс для ваших пользователей.

Оцените материал
Добавить комментарий

Капча загружается...