Панель поиска флаттера с автозаполнением - PullRequest
0 голосов
/ 26 апреля 2018

Я ищу строку поиска в флаттер-документах, но не могу ее найти, есть ли виджет для панели поиска с автозаполнением в панели приложений. Например, у меня есть значок поиска на панели приложений. Когда вы нажмете это, появится окно поиска, а при вводе вы увидите автозаполнение из выпадающего списка. Мне удалось реализовать это, но это не легко использовать, потому что мне нужно раскрывающееся меню, чтобы показать автозаполнение предложения, а затем использовать предложение для нового маршрута, если выбран.

Здесь поисковое действие

here the example image what I want to achieve

Ответы [ 3 ]

0 голосов
/ 17 июля 2019

этот плагин будет полезен для вас, loader_search_bar

Виджет Flutter, интегрирующий функцию поля поиска в панель приложения, позволяющую получать обратные вызовы изменения запроса и автоматически загружать новый набор данных в ListView. Он заменяет стандартный виджет AppBar и должен работать под элементом Scaffold в дереве виджетов для правильной работы.

enter image description here

Начало работы Чтобы начать использовать SearchBar, вставьте его вместо элемента AppBar в виджете Scaffold. Независимо от варианта использования должен быть указан именованный аргумент defaultBar, который в основном является виджетом, который будет отображаться, когда SearchBar не находится в активированном состоянии:

@override
Widget build(BuildContext context) {
   return Scaffold(
 appBar: SearchBar(
   defaultBar: AppBar(
     leading: IconButton(
       icon: Icon(Icons.menu),
       onPressed: _openDrawer,
     ),
     title: Text('Default app bar title'),
   ),
   ...
 ),
 body: _body,
 drawer: _drawer,
   );
}

Необязательные атрибуты

  • searchHint - строка подсказки отображается до тех пор, пока пользователь не введет какой-либо текст,
  • initialQuery - значение запроса, отображаемое впервые в поле поиска,
  • iconified - логическое значение, указывающее способ представления неактивированной панели поиска: истина, если виджет должен быть показан как элемент действия в defaultBar, false, если виджет должен быть объединен с defaultBar (в этом случае отображается только начальный значок виджета по умолчанию и поля ввода поиска),
  • autofocus - логическое значение, определяющее, должен ли текстовое поле поиска получать фокус всякий раз, когда оно становится видимым,
  • autoActive -,
  • attrs - экземпляр класса SearchBarAttrs, позволяющий указать часть точных значений, используемых при построении виджета (например, цвета панели поиска, размер текста, радиус границы),
  • controller - объект SearchBarController, обеспечивающий взаимодействие с текущим состоянием виджета,
  • searchItem - определение того, как создать и разместить виджет элемента поиска в панели приложения,
  • overlayStyle - яркость наложения строки состояния, применяемая при активации виджета.

Запрос обратных вызовов

Чтобы получать уведомления о пользовательском вводе, укажите функции обратного вызова onQueryChanged и / или onQuerySubmitted, которые получают в качестве аргумента текущую строку запроса:

appBar: SearchBar(
   ...
   onQueryChanged: (query) => _handleQueryChanged(context, query),
   onQuerySubmitted: (query) => _handleQuerySubmitted(context, query),
),

QuerySetLoader

Передав объект QuerySetLoader в качестве аргумента, можно дополнительно воспользоваться результатами автоматического построения результатов поиска в виде виджета ListView при каждом изменении поискового запроса:

appBar: SearchBar(
  ...
   loader: QuerySetLoader<Item>(
   querySetCall: _getItemListForQuery,
   itemBuilder: _buildItemWidget,
   loadOnEachChange: true,
   animateChanges: true,
  ),
),

List<Item> _getItemListForQuery(String query) { ... }

Widget _buildItemWidget(Item item) { ... }
  • querySetCall - функция, преобразующая поисковый запрос в список элементов, которые затем отображаются в ListView (обязательно),
  • itemBuilder - функция создания объекта Widget для полученного элемента, вызываемая при построении ListView для каждого элемента набора результатов (обязательно),
  • loadOnEachChange - логическое значение, указывающее, должен ли querySetCall запускаться при каждом изменении запроса; если ложный набор запросов загружается после того, как пользователь отправляет запрос,
  • animateChanges - определяет, должны ли анимироваться операции вставки и удаления ListView.

SearchItem

Указание этого параметра позволяет настроить способ поиска и позиционирование элемента поиска на панели приложения. Это может быть виджет действия или меню. Независимо от того, какой из этих двух выбран, два аргумента конструктора могут быть переданы:

  • builder - функция, получающая текущий BuildContext и возвращающая Widget для действия или PopupMenuItem для пункта меню,
  • gravity - может быть одним из значений SearchItemGravity: начало, конец или точно. Если аргументы не переданы, SearchBar создаст элемент по умолчанию, который является значком поискового действия со стартовой гравитацией.

SearchItem.action

enter image description here

appBar: SearchBar(
  // ...
  searchItem: SearchItem.action(
    builder: (_) => Padding(
      padding: EdgeInsets.all(12.0),
      child: Icon(
        Icons.find_in_page,
        color: Colors.indigoAccent,
      ),
    ),
    gravity: SearchItemGravity.exactly(1),
  ),
)

SearchItem.menu

enter image description here

appBar: SearchBar(
  // ...
  searchItem: SearchItem.menu(
    builder: (_) => PopupMenuItem(
      child: Text("Search  ?"),
      value: "search",
    ),
    gravity: SearchItemGravity.end,
  ),
)

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

надеюсь, это поможет вам.

0 голосов
/ 18 июля 2019

Это на самом деле очень просто. Вы можете сослаться на ответы выше для деталей. Давайте выполните следующие шаги:

  • Создайте список элементов, которые мы хотим иметь в меню автозаполнения, назовем его autoList
  • Создать еще один пустой список с именем FilterList
  • Добавить все значения autoList в filterList
void initState() {
filteredList.addAll(autoList);
}
  • Создание пользовательского виджета панели поиска с текстовым полем

  • мы получим «значение», то есть текст, введенный из этого текстового поля: например. TextFiled (OnChange (значение) {})

  • Предполагая, что в нашем автолисте есть строки, напишите:

filteredList.removeWhere((i) => i.contains(value.toString())==false); 

Полный виджет TextField будет выглядеть так:

TextField(
     onChanged: (value) {
     setState(() {
     filteredList.clear(); //for the next time that we search we want the list to be unfilterted                            
     filteredList.addAll(autoList); //getting list to original state

//removing items that do not contain the entered Text                                                            
     filteredList.removeWhere((i) => i.contains(value.toString())==false); 

//following is just a bool parameter to keep track of lists
     searched=!searched;
     });


    },
  controller: editingController,
  decoration: InputDecoration(
  border: InputBorder.none,
  labelText: "Search for the filtered list",
  prefixIcon: Icon(Icons.search),
   ),
    ),

Теперь, вдоль панели поиска, нам просто нужно отобразить FilterList с ListViewBuilder. сделано :)

0 голосов
/ 30 июня 2018

Вы можете использовать стек для достижения эффекта выпадающего списка автозаполнения. Пример ниже имеет 2 контейнера - оба держат ListView как дочерние объекты. Один содержит результаты поиска, другой содержит некоторый случайный текст в качестве содержимого для тела. ListView (результат поиска) размещается внутри объекта Align, а для свойства выравнивания устанавливается значение Alignment.topCenter. Это гарантирует, что список появится сверху, чуть ниже AppBar.

Обновлен Пост (принятый ответ), упомянутый в комментариях, для полной демонстрации.

Как объяснено выше:

    @override
      Widget build(BuildContext context) {
        return new Scaffold(
            key: key,
            appBar: buildBar(context),
            body: new Stack(
              children: <Widget>[
                new Container(
                  height: 300.0,
                  padding: EdgeInsets.all(10.0),
                  child: new DefaultTabController(length: 5, child: mainTabView),
                ),
                displaySearchResults(),
              ],
            ));
      }


      Widget displaySearchResults() {
        if (_IsSearching) {
          return new Align(
              alignment: Alignment.topCenter,
              //heightFactor: 0.0,
              child: searchList());
        } else {
          return new Align(alignment: Alignment.topCenter, child: new Container());
        }
      }

Полная демонстрация

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

  @override
  _SearchListState createState() => new _SearchListState();
}

class _SearchListState extends State<SearchList> {
  Widget appBarTitle = new Text(
    "",
    style: new TextStyle(color: Colors.white),
  );
  Icon actionIcon = new Icon(
    Icons.search,
    color: Colors.white,
  );
  final key = new GlobalKey<ScaffoldState>();
  final TextEditingController _searchQuery = new TextEditingController();
  List<SearchResult> _list;
  bool _IsSearching;
  String _searchText = "";
  String selectedSearchValue = "";

  _SearchListState() {
    _searchQuery.addListener(() {
      if (_searchQuery.text.isEmpty) {
        setState(() {
          _IsSearching = false;
          _searchText = "";
        });
      } else {
        setState(() {
          _IsSearching = true;
          _searchText = _searchQuery.text;
        });
      }
    });
  }

  @override
  void initState() {
    super.initState();
    _IsSearching = false;
    createSearchResultList();
  }

  void createSearchResultList() {
    _list = <SearchResult>[
      new SearchResult(name: 'Google'),
      new SearchResult(name: 'IOS'),
      new SearchResult(name: 'IOS2'),
      new SearchResult(name: 'Android'),
      new SearchResult(name: 'Dart'),
      new SearchResult(name: 'Flutter'),
      new SearchResult(name: 'Python'),
      new SearchResult(name: 'React'),
      new SearchResult(name: 'Xamarin'),
      new SearchResult(name: 'Kotlin'),
      new SearchResult(name: 'Java'),
      new SearchResult(name: 'RxAndroid'),
    ];
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        key: key,
        appBar: buildBar(context),
        body: new Stack(
          children: <Widget>[
            new Container(
              height: 300.0,
              padding: EdgeInsets.all(10.0),
              child: new Container(
                child: ListView(
                  children: <Widget>[
                    new Text("Hello World!"),
                    new Text("Hello World!"),
                    new Text("Hello World!"),
                    new Text("Hello World!"),
                    new Text("Hello World!"),
                    new Text("Hello World!"),
                    new Text("Hello World!"),
                    new Text("Hello World!"),
                    new Text("Hello World!"),
                    new Text("Hello World!"),
                    new Text("Hello World!"),
                    new Text("Hello World!"),
                    new Text("Hello World!"),
                  ],
                ),
              ),
            ),
            displaySearchResults(),
          ],
        ));
  }

  Widget displaySearchResults() {
    if (_IsSearching) {
      return new Align(
          alignment: Alignment.topCenter,
          child: searchList());
    } else {
      return new Align(alignment: Alignment.topCenter, child: new Container());
    }
  }

  ListView searchList() {
    List<SearchResult> results = _buildSearchList();
    return ListView.builder(
      itemCount: _buildSearchList().isEmpty == null ? 0 : results.length,
      itemBuilder: (context, int index) {
        return Container(
          decoration: new BoxDecoration(
              color: Colors.grey[100],
            border: new Border(
              bottom: new BorderSide(
                  color: Colors.grey,
                width: 0.5
              )
          )
          ),

          child: ListTile(
            onTap: (){},
            title: Text(results.elementAt(index).name,
                style: new TextStyle(fontSize: 18.0)),
          ),
        );
      },
    );
  }

  List<SearchResult> _buildList() {
    return _list.map((result) => new SearchResult(name: result.name)).toList();
  }

  List<SearchResult> _buildSearchList() {
    if (_searchText.isEmpty) {
      return _list.map((result) => new SearchResult(name: result.name)).toList();
    } else {
      List<SearchResult> _searchList = List();
      for (int i = 0; i < _list.length; i++) {
        SearchResult result = _list.elementAt(i);
        if ((result.name).toLowerCase().contains(_searchText.toLowerCase())) {
          _searchList.add(result);
        }
      }
      return _searchList
          .map((result) => new SearchResult(name: result.name))
          .toList();
    }
  }

  Widget buildBar(BuildContext context) {
    return new AppBar(
      centerTitle: true,
      title: appBarTitle,
      actions: <Widget>[
        new IconButton(
          icon: actionIcon,
          onPressed: () {
            _displayTextField();
          },
        ),

        // new IconButton(icon: new Icon(Icons.more), onPressed: _IsSearching ? _showDialog(context, _buildSearchList()) : _showDialog(context,_buildList()))
      ],
    );
  }

  String selectedPopupRoute = "My Home";
  final List<String> popupRoutes = <String>[
    "My Home",
    "Favorite Room 1",
    "Favorite Room 2"
  ];

  void _displayTextField() {
    setState(() {
      if (this.actionIcon.icon == Icons.search) {
        this.actionIcon = new Icon(
          Icons.close,
          color: Colors.white,
        );
        this.appBarTitle = new TextField(
          autofocus: true,
          controller: _searchQuery,
          style: new TextStyle(
            color: Colors.white,
          ),
        );

        _handleSearchStart();
      } else {
        _handleSearchEnd();
      }
    });
  }

  void _handleSearchStart() {
    setState(() {
      _IsSearching = true;
    });
  }

  void _handleSearchEnd() {
    setState(() {
      this.actionIcon = new Icon(
        Icons.search,
        color: Colors.white,
      );
      this.appBarTitle = new Text(
        "",
        style: new TextStyle(color: Colors.white),
      );
      _IsSearching = false;
      _searchQuery.clear();
    });
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...