Использование оверлея для создания автозаполнения для Flutter Web - PullRequest
0 голосов
/ 26 мая 2020

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

Цель: 1) Пользователь вводит его. Если длина превышает 0, он будет отображать данные (после краткого сообщения Загрузка ..) 2) Как только пользователь щелкает свой выбор на Overlay, он использует эти данные и помещает их в текстовое поле 3) Пользователь может снова начать вводить или удалить текущие данные и процесс может повторяться

Ошибки: 1) Нулевое значение оверлея может вызвать у меня проблемы с закрытием оверлея после его завершения 2) Появляются несколько слушателей, представляющих проблемы, подобные приведенным ниже:

Oklahoma City
controllerText : Oklahoma City selectedText: Oklahoma City
in snapshot.hasData Oklahoma City
in snapshot.hasData Oklahoma City
in snapshot.hasData Oklahoma City
in snapshot.hasData Oklahoma City

Текущий код:

import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

Future<dynamic> fetchAlbum(String query) async {
  if (query.length > 0) {
    final response = await http.get(
      'https://cors-anywhere.herokuapp.com/https://en.wikipedia.org/w/api.php?action=opensearch&search=$query&limit=20&format=json',
    );

    if (response.statusCode == 200) {
      // If the server did return a 200 OK response,
      // then parse the JSON.
      return List<dynamic>.from(json.decode(response.body).map((x) => x));
    } else {
      // If the server did not return a 200 OK response,
      // then throw an exception.
      throw Exception('Failed to fetch items');
    }
  }
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            CountriesField(),
            Text('Example text'),
          ],
        ),
      ),
    );
  }
}

class CountriesField extends StatefulWidget {
  @override
  _CountriesFieldState createState() => _CountriesFieldState();
}

class _CountriesFieldState extends State<CountriesField> {
  String _selectedText;
  Future<dynamic> _futureAlbum;

  // Create a text controller and use it to retrieve the current value
  // of the TextField.
  final TextEditingController _controller = TextEditingController();

  final FocusNode _focusNode = FocusNode();

  OverlayEntry _overlayEntry;

  final LayerLink _layerLink = LayerLink();

  bool _closed = false;

  @override
  void initState() {
    super.initState();
    _controller.addListener(() {
      print(
          'controllerText : ${_controller.text} selectedText: ${_selectedText}');
      if (_controller.text != _selectedText) {
        if (!_closed && this._overlayEntry != null) {
          this._overlayEntry.remove();
          _closed = false;
        }
        this._overlayEntry = this._createOverlayEntry();
        Overlay.of(context).insert(this._overlayEntry);
      }
      setState(() {
        _futureAlbum = fetchAlbum(_controller.text);
      });
    });
    _focusNode.addListener(() {
      if (!_focusNode.hasFocus) {
        _closed = true;
        this._overlayEntry.remove();
      }
    });
  }

  OverlayEntry _createOverlayEntry() {
    RenderBox renderBox = context.findRenderObject();
    var size = renderBox.size;

    return OverlayEntry(
      builder: (context) => Positioned(
        width: size.width,
        child: CompositedTransformFollower(
          link: this._layerLink,
          showWhenUnlinked: false,
          offset: Offset(0.0, size.height + 5.0),
          child: Material(
            elevation: 4.0,
            child: FutureBuilder<dynamic>(
              future: _futureAlbum,
              builder: (context, snapshot) {
                if (snapshot.hasData) {
                  print('in snapshot.hasData ${_controller.text}');
                  List<dynamic> b = snapshot.data[1];
                  if (b.length > 0) {
                    return ListView.builder(
                      padding: EdgeInsets.zero,
                      shrinkWrap: true,
                      itemCount: b.length,
                      itemBuilder: (context, index) {
                        String text = b[index];
                        return GestureDetector(
                          onPanDown: (_) {
                            print(text);
                            _selectedText = text;
                            _controller.text = text;
                          },
                          child: ListTile(
                            title: Text(text),
                          ),
                        );
                      },
                    );
                  } else {
                    return Text('No items found');
                  }
                } else if (snapshot.hasError) {
                  return Text("${snapshot.error}");
                }
                // By default, show a loading spinner.
                return Text('Loading...');
              },
            ),
          ),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return CompositedTransformTarget(
      link: this._layerLink,
      child: TextFormField(
        focusNode: this._focusNode,
        controller: _controller,
        decoration: InputDecoration(labelText: 'Country'),
      ),
    );
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...