Flutter overlayEntry не обновляет содержимое после изменения состояния

Я пытаюсь реализовать функцию наложения для текстового поля, которое показывает определенное состояние в зависимости от ввода пользователя. Когда пользователь нажимает на текстовое поле, оно отображает наложение, которое должно отображать некоторую информацию, пока пользователь пишет, так же, как работает панель поиска в веб-браузере.

Моя проблема в том, что содержимое OverlayEntry не обновляется одновременно с изменением пользовательского ввода, оно изменяется только при повторном открытии Overlay.

Ожидаемое поведение

Текущее поведение

Для тестирования этой функциональности я просто передаю одно и то же значение из текстового поля в оверлей.

Это мой код:

Домашний класс

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
        onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
        child: Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Center(
            child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  CustomTextField(),
                ]),
            // This trailing comma makes auto-formatting nicer for build methods.
          ),
        ));
  }
}

Пользовательский класс текстового поля:

class CustomTextField extends StatefulWidget {
  CustomTextField({Key? key}) : super(key: key);

  @override
  State<CustomTextField> createState() => _CustomTextFieldState();
}

class _CustomTextFieldState extends State<CustomTextField>
    with TickerProviderStateMixin {
  TextEditingController controlador = TextEditingController();
  FocusNode nodeUno = FocusNode();
  OverlayEntry? _overlayEntry;
  GlobalKey globalKey = GlobalKey();
  final LayerLink _layerLink = LayerLink();
  String inputText = '';

  @override
  void initState() {
    super.initState();
    OverlayState? overlayState = Overlay.of(context);
    WidgetsBinding.instance!.addPostFrameCallback((_) {
      globalKey;
    });

    nodeUno.addListener(() {
      if (nodeUno.hasFocus) {
        _overlayEntry = _createOverlay(inputText);

        overlayState!.insert(_overlayEntry!);
      } else {
        _overlayEntry!.remove();
      }
    });
  }

  OverlayEntry _createOverlay([String? text]) {
    RenderBox renderBox = context.findRenderObject() as RenderBox;

    var size = renderBox.size;
    return OverlayEntry(
        builder: (context) => Positioned(
              width: size.width,
              child: CompositedTransformFollower(
                link: _layerLink,
                showWhenUnlinked: false,
                offset: Offset(0.0, size.height + 5.0),
                child: Material(
                  elevation: 5.0,
                  child: Column(
                    children: [
                      ListTile(
                        title: text != '' ? Text(text!) : const Text('data'),
                      ),
                    ],
                  ),
                ),
              ),
            ));
  }

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: 250,
      child: CompositedTransformTarget(
        link: _layerLink,
        child: TextField(
          focusNode: nodeUno,
          controller: controlador,
          onChanged: (value) {
            print(value);
            setState(() {
              inputText = value;
            });
          },
        ),
      ),
    );
  }
}
Шаблоны Angular PrimeNg
Шаблоны Angular PrimeNg
Как привнести проверку типов в наши шаблоны Angular, использующие компоненты библиотеки PrimeNg, и настроить их отображение с помощью встроенной...
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Если вы веб-разработчик (или хотите им стать), то вы наверняка гик и вам нравятся "Звездные войны". А как бы вы хотели, чтобы фоном для вашего...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Начала с розового дизайна
Начала с розового дизайна
Pink Design - это система дизайна Appwrite с открытым исходным кодом для создания последовательных и многократно используемых пользовательских...
Шлюз в PHP
Шлюз в PHP
API-шлюз (AG) - это сервер, который действует как единая точка входа для набора микросервисов.
14 Задание: Типы данных и структуры данных Python для DevOps
14 Задание: Типы данных и структуры данных Python для DevOps
проверить тип данных используемой переменной, мы можем просто написать: your_variable=100
0
0
86
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

class CustomTextField extends StatefulWidget {
  CustomTextField({Key? key}) : super(key: key);

  @override
  State<CustomTextField> createState() => _CustomTextFieldState();
}

class _CustomTextFieldState extends State<CustomTextField>
    with TickerProviderStateMixin {
  TextEditingController controlador = TextEditingController();
  FocusNode nodeUno = FocusNode();
  OverlayEntry? _overlayEntry;
  GlobalKey globalKey = GlobalKey();
  final LayerLink _layerLink = LayerLink();
  String inputText = '';
  OverlayState? overlayState;
  bool popoverOpened = false;

  @override
  void initState() {
    super.initState();
    _overlayEntry = null;
    overlayState = Overlay.of(context);
    WidgetsBinding.instance!.addPostFrameCallback((_) {
      globalKey;
    });

    nodeUno.addListener(() {
      if (nodeUno.hasFocus) {
        _overlayEntry = _createOverlay(inputText);
        overlayState!.insert(_overlayEntry!);
      } else {
        if (_overlayEntry != null) {
          _overlayEntry?.remove();
          _overlayEntry = null;
        }
      }
    });
  }

  OverlayEntry _createOverlay([String? text]) {
    RenderBox renderBox = context.findRenderObject() as RenderBox;

    if (_overlayEntry != null && popoverOpened) {
      _overlayEntry!.remove();
    }
    popoverOpened = true;
    var size = renderBox.size;
    return OverlayEntry(
        builder: (context) => Positioned(
              width: size.width,
              child: CompositedTransformFollower(
                link: _layerLink,
                showWhenUnlinked: false,
                offset: Offset(0.0, size.height + 5.0),
                child: OverlayClass(val: inputText),
              ),
            ));
  }

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: 250,
      child: CompositedTransformTarget(
        link: _layerLink,
        child: TextField(
          focusNode: nodeUno,
          controller: controlador,
          onChanged: (value) {
            print(value);
            setState(() {
              inputText = value;
              _overlayEntry = _createOverlay(inputText);
              overlayState!.insert(_overlayEntry!);
            });
          },
        ),
      ),
    );
  }
}

Другие вопросы по теме