Flutter: OptionsViewBuilder не полностью выбирается в двух текстовых полях автозаполнения

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

У меня есть два виджета Автозаполнения, и мне нужно, чтобы их текстовые поля располагались рядом. Кроме того, я хочу, чтобы optionsViewBuilder для обоих занимал всю ширину от начала первого текстового поля до конца второго. Для достижения этого я использовал CompositedTransformTarget и CompositedTransformFollower, и это работает идеально, как задумано.

Однако логика не работает идеально. Я сталкиваюсь с проблемой со вторым TextField: только область непосредственно под этим TextFieldSelectable и скроллируемая, в то время как область непосредственно под первым TextField невыбираемая и нескроллируемая для второго optionsViewBuilder.

Только область в черном квадрате доступна для выбора или прокрутки для второго виджета автозаполнения, как показано на этом фото введите описание изображения здесь

class MyWidget extends StatelessWidget {
  const MyWidget({super.key});

  @override
  Widget build(BuildContext context) {
    final LayerLink layerLink = LayerLink();
    final List<String> fruits = [
      'Apple',
      'Banana',
      'Cherry',
      'Grapes',
    ];
    final List<String> vegetables = [
      'Carrot',
      'Broccoli',
      'Spinach',
      'Potato',
    ];
    return Column(
      children: [
        SizedBox(
          height: 200,
        ),
        CompositedTransformTarget(
          link: layerLink,
          child: Row(
            children: [
              Flexible(
                child: Autocomplete(
                  optionsBuilder: (textEditingValue) => fruits,
                  optionsViewBuilder: (context, onSelected, options) =>
                      CompositedTransformFollower(
                    targetAnchor: Alignment.bottomLeft,
                    link: layerLink,
                    child: MyAutocompleteOptionsViewBuilder<String>(
                      options: options,
                      onSelected: onSelected,
                    ),
                  ),
                ),
              ),
              Flexible(
                child: Autocomplete(
                  optionsBuilder: (textEditingValue) => vegetables,
                  optionsViewBuilder: (context, onSelected, options) =>
                      CompositedTransformFollower(
                    targetAnchor: Alignment.bottomLeft,
                    link: layerLink,
                    child: MyAutocompleteOptionsViewBuilder<String>(
                      options: options,
                      onSelected: onSelected,
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ],
    );
  }
}

class MyAutocompleteOptionsViewBuilder<T> extends StatelessWidget {
  const MyAutocompleteOptionsViewBuilder({
    super.key,
    required this.options,
    required this.onSelected,
  });
  final Iterable<T> options;
  final void Function(T) onSelected;
  @override
  Widget build(BuildContext context) {
    return Align(
      alignment: Alignment.topLeft,
      child: Material(
        elevation: 4.0,
        color: Colors.white,
        child: ConstrainedBox(
          constraints: BoxConstraints(
            maxHeight: MediaQuery.of(context).size.height * 0.2,
          ),
          child: ListView.builder(
            shrinkWrap: true,
            padding: EdgeInsets.zero,
            itemCount: options.length,
            itemBuilder: (BuildContext context, int index) {
              final option = options.elementAt(index);
              return ListTile(
                title: Text(option.toString()),
                onTap: () {
                  onSelected(option);
                },
              );
            },
          ),
        ),
      ),
    );
  }
}

Ответ или решение

Чтобы решить проблему с возможностью выбора опций в двух виджетах Autocomplete в Flutter, когда они располагаются бок о бок и используют CompositedTransformTarget и CompositedTransformFollower, нужно учесть несколько ключевых моментов, касающихся архитектуры виджетов и их взаимодействия.

Проблема

Из описания видно, что область, которая отвечает за отображение опций для второго текстового поля, ограничена только ниже самого поля. Это вызвано тем, что вы используете один и тот же LayerLink для обоих виджетов, что приводит к тому, что CompositedTransformFollower для второго виджета перекрывает (или аффектит) поведение первого, из-за чего область взаимодействия оказывается разделенной.

По сути, каждый из ваших CompositedTransformFollower использует один и тот же LayerLink. Это считается источником вашей проблемы. Для каждого текстового поля вам нужно создать отдельный LayerLink, чтобы их выпадающие списки не конфликтовали между собой.

Решение

Создайте два отдельных LayerLink — один для каждого виджета Autocomplete. Вот как вы можете изменить ваш код, чтобы это реализовать:

class MyWidget extends StatelessWidget {
  const MyWidget({super.key});

  @override
  Widget build(BuildContext context) {
    final LayerLink fruitLayerLink = LayerLink();
    final LayerLink vegetableLayerLink = LayerLink();
    final List<String> fruits = ['Apple', 'Banana', 'Cherry', 'Grapes'];
    final List<String> vegetables = ['Carrot', 'Broccoli', 'Spinach', 'Potato'];

    return Column(
      children: [
        SizedBox(height: 200),
        Row(
          children: [
            Flexible(
              child: Autocomplete(
                optionsBuilder: (textEditingValue) => fruits,
                optionsViewBuilder: (context, onSelected, options) => CompositedTransformFollower(
                  link: fruitLayerLink,
                  targetAnchor: Alignment.bottomLeft,
                  child: MyAutocompleteOptionsViewBuilder<String>(
                    options: options,
                    onSelected: onSelected,
                  ),
                ),
              ),
            ),
            Flexible(
              child: Autocomplete(
                optionsBuilder: (textEditingValue) => vegetables,
                optionsViewBuilder: (context, onSelected, options) => CompositedTransformFollower(
                  link: vegetableLayerLink,
                  targetAnchor: Alignment.bottomLeft,
                  child: MyAutocompleteOptionsViewBuilder<String>(
                    options: options,
                    onSelected: onSelected,
                  ),
                ),
              ),
            ),
          ],
        ),
      ],
    );
  }
}

class MyAutocompleteOptionsViewBuilder<T> extends StatelessWidget {
  const MyAutocompleteOptionsViewBuilder({
    super.key,
    required this.options,
    required this.onSelected,
  });

  final Iterable<T> options;
  final void Function(T) onSelected;

  @override
  Widget build(BuildContext context) {
    return Align(
      alignment: Alignment.topLeft,
      child: Material(
        elevation: 4.0,
        color: Colors.white,
        child: ConstrainedBox(
          constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.2),
          child: ListView.builder(
            shrinkWrap: true,
            padding: EdgeInsets.zero,
            itemCount: options.length,
            itemBuilder: (BuildContext context, int index) {
              final option = options.elementAt(index);
              return ListTile(
                title: Text(option.toString()),
                onTap: () {
                  onSelected(option);
                },
              );
            },
          ),
        ),
      ),
    );
  }
}

Заключение

Теперь код использует отдельные LayerLink для каждого из полей Autocomplete, что позволяет пользователю взаимодействовать с выпадающими списками без каких-либо проблем. Важно помнить, что разделение логики отображения между разными виджетами является ключевым моментом при использовании анимации и взаимодействий в Flutter.

Примечания

  1. Убедитесь, что версии ваших зависимостей и самой библиотеки Flutter актуальны.
  2. Тестируйте на разных устройствах, чтобы убедиться в корректности работы.

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

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

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