How to implement a Flutter Search App Bar
Asked Answered
D

4

22

There are a lot of tutorials but rather than help me to move forward, I get lost in all possible options or I don't know how to improve the code (I would like to use an application that displays a list that use more than only the name of three fruits or three cities ?)

I found tutorials to create a nice SearchBar with the ability to display the result based on the first letters typed.

I don't understand how to edit the tutorial with a data list that includes a title associated with the content. I don't understand how to display the result if the first letter is lowercase or uppercase. Would it be possible to help me to make a simple basic code that could serve everyone including beginners like me?

DataList.dart

List<ListWords>  listWords = [
  ListWords('oneWord', 'OneWord definition'),
  ListWords('twoWord', 'TwoWord definition.'),
  ListWords('TreeWord', 'TreeWord definition'),
];

class ListWords {
  String titlelist;
  String definitionlist;

  ListWords(String titlelist, String definitionlist) {
    this.titlelist = titlelist;
    this.definitionlist = definitionlist;
  }
}

Searchbar.dart

import 'package:flutter/material.dart';
import 'package:test_searchbar/DataList.dart';

class SearchBar extends StatelessWidget {


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Search App'),
        actions: <Widget>[
          IconButton(icon: Icon(Icons.search),
              onPressed: () {
                showSearch(context: context, delegate: DataSearch(listWords));
              })
        ],
      ),
      drawer: Drawer(),
    );
  }
}

class DataSearch extends SearchDelegate<String> {

  final List<ListWords> listWords;

  DataSearch(this.listWords);


  @override
  List<Widget> buildActions(BuildContext context) {
    //Actions for app bar
    return [IconButton(icon: Icon(Icons.clear), onPressed: () {
      query = '';
    })];
  }

  @override
  Widget buildLeading(BuildContext context) {
    //leading icon on the left of the app bar
    return IconButton(
        icon: AnimatedIcon(icon: AnimatedIcons.menu_arrow,
          progress: transitionAnimation,
        ),
        onPressed: () {
          close(context, null);
        });
  }

  @override
  Widget buildResults(BuildContext context) {
    // show some result based on the selection
    return Center(
      child: Text(query),

    );
  }

  @override
  Widget buildSuggestions(BuildContext context) {
    // show when someone searches for something
    final suggestionList = query.isEmpty
        ? listWords
        : listWords.where((p) => p.startsWith(query)).toList();



    return ListView.builder(itemBuilder: (context, index) => ListTile(
      onTap: () {
        showResults(context);
      },
      trailing: Icon(Icons.remove_red_eye),
      title: RichText(
        text: TextSpan(
            text: suggestionList[index].titlelist.substring(0, query.length),
            style: TextStyle(
                color: Colors.red, fontWeight: FontWeight.bold),
            children: [
              TextSpan(
                  text: suggestionList[index].titlelist.substring(query.length),
                  style: TextStyle(color: Colors.grey))
            ]),
      ),
    ),
      itemCount: suggestionList.length,
    );
  }
}
Discriminative answered 18/11, 2019 at 6:22 Comment(1)
Also besides the answer given below for searching effectively, instead of startsWithuse contains method. Example String.contains(RegExp(searchText, caseSensitive: false)) which will return you more accurate results.Generous
S
43

To create a search appbar, you will need a stateful widget with the following code,

Inside your State class,

  TextEditingController _searchQueryController = TextEditingController();
  bool _isSearching = false;
  String searchQuery = "Search query";

Inside Scaffold, your appbar should be like,

appBar: AppBar(
        leading: _isSearching ? const BackButton() : Container(),
        title: _isSearching ? _buildSearchField() : _buildTitle(context),
        actions: _buildActions(),
      ),

Define the required following methods for displaying and managing searchbar,

Widget _buildSearchField() {
    return TextField(
      controller: _searchQueryController,
      autofocus: true,
      decoration: InputDecoration(
        hintText: "Search Data...",
        border: InputBorder.none,
        hintStyle: TextStyle(color: Colors.white30),
      ),
      style: TextStyle(color: Colors.white, fontSize: 16.0),
      onChanged: (query) => updateSearchQuery(query),
    );
  }

  List<Widget> _buildActions() {
    if (_isSearching) {
      return <Widget>[
        IconButton(
          icon: const Icon(Icons.clear),
          onPressed: () {
            if (_searchQueryController == null ||
                _searchQueryController.text.isEmpty) {
              Navigator.pop(context);
              return;
            }
            _clearSearchQuery();
          },
        ),
      ];
    }

    return <Widget>[
      IconButton(
        icon: const Icon(Icons.search),
        onPressed: _startSearch,
      ),
    ];
  }

  void _startSearch() {
    ModalRoute.of(context)
        .addLocalHistoryEntry(LocalHistoryEntry(onRemove: _stopSearching));

    setState(() {
      _isSearching = true;
    });
  }

  void updateSearchQuery(String newQuery) {
    setState(() {
      searchQuery = newQuery;
    });
  }

  void _stopSearching() {
    _clearSearchQuery();

    setState(() {
      _isSearching = false;
    });
  }

  void _clearSearchQuery() {
    setState(() {
      _searchQueryController.clear();
      updateSearchQuery("");
    });
  }

This is the best way to implement an app searchbar in any flutter screen.

Silversmith answered 18/11, 2019 at 6:28 Comment(6)
Why create your own search bar?. Just use the showSearch() from flutterOas
To add and manage custom functionalities. I found this as a better option than showSearch();Silversmith
Thank you for responding quickly. As Tinus Jackson said, is not the use of show search the best way to use the Flutter method? Is it not possible from show search to use a complex list from a data file? Same for displaying the first letter, etc. this is not possible with show search? Thank you for your time, I test all that and come back maybe with other questions ...Discriminative
It depends on you. How you want to use your search requirements. In my opinion, I found this method as best to use searchbar as an Appbar. Try and check yourself.Silversmith
Thanks Jay Mungara. I will also test your method to compare (and learn !!!).Discriminative
To make this work on change modify "onChanged: (query) => updateSearchQuery," to "onChanged: (query) => updateSearchQuery(query),"Rasia
D
1

Finally, I managed to do this. This is a good starting point for the Search Show in a list. Does this are correct?

DataList.dart

List<ListWords>  listWords = [
  ListWords('oneWord', 'OneWord definition'),
  ListWords('twoWord', 'TwoWord definition.'),
  ListWords('TreeWord', 'TreeWord definition'),
];

class ListWords {
  String titlelist;
  String definitionlist;

  ListWords(String titlelist, String definitionlist) {
    this.titlelist = titlelist;
    this.definitionlist = definitionlist;
  }
}

SearchBar.dart

import 'dart:core';
import 'package:flutter/material.dart';
import 'package:test_searchbar/DataList.dart';
import 'package:test_searchbar/detail.dart';

class SearchBar extends StatelessWidget {


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Search App'),
        actions: <Widget>[
          IconButton(icon: Icon(Icons.search),
              onPressed: () {
                showSearch(context: context, delegate: DataSearch(listWords));
              })
        ],
      ),
      body: Center(
          child: Text('default content')
      ),
      drawer: Drawer(),
    );
  }
}

class DataSearch extends SearchDelegate<String> {

  final List<ListWords> listWords;

  DataSearch(this.listWords);

  @override
  List<Widget> buildActions(BuildContext context) {
    //Actions for app bar
    return [IconButton(icon: Icon(Icons.clear), onPressed: () {
      query = '';
    })];
  }

  @override
  Widget buildLeading(BuildContext context) {
    //leading icon on the left of the app bar
    return IconButton(
        icon: AnimatedIcon(icon: AnimatedIcons.menu_arrow,
          progress: transitionAnimation,
        ),
        onPressed: () {
          close(context, null);
        });
  }

  @override
  Widget buildResults(BuildContext context) {
    // show some result based on the selection
    final suggestionList = listWords;

    return ListView.builder(itemBuilder: (context, index) => ListTile(

      title: Text(listWords[index].titlelist),
      subtitle: Text(listWords[index].definitionlist),
    ),
      itemCount: suggestionList.length,
    );
  }

  @override
  Widget buildSuggestions(BuildContext context) {
    // show when someone searches for something

    final suggestionList = query.isEmpty
        ? listWords
        : listWords.where((p) => p.titlelist.contains(RegExp(query, caseSensitive: false))).toList();


    return ListView.builder(itemBuilder: (context, index) => ListTile(
      onTap: () {
        Navigator.push(
          context,
          MaterialPageRoute(
            builder: (context) => Detail(listWordsDetail: suggestionList[index]),
          ),
        );
      },
      trailing: Icon(Icons.remove_red_eye),
      title: RichText(
        text: TextSpan(
            text: suggestionList[index].titlelist.substring(0, query.length),
            style: TextStyle(
                color: Colors.red, fontWeight: FontWeight.bold),
            children: [
              TextSpan(
                  text: suggestionList[index].titlelist.substring(query.length),
                  style: TextStyle(color: Colors.grey)),
            ]),
      ),
    ),
      itemCount: suggestionList.length,
    );
  }
}

detail.dart

import 'package:flutter/material.dart';
import 'package:test_searchbar/DataList.dart';

class Detail extends StatelessWidget {

  final ListWords listWordsDetail;

  Detail({Key key, @required this.listWordsDetail}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          brightness: Brightness.dark,
          title: const Text('Détail', style: TextStyle(color: Colors.white)),
          iconTheme: IconThemeData(color: Colors.white),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(listWordsDetail.titlelist +' (on detail page)'),
              Text(listWordsDetail.definitionlist),
            ],
          ),
        )
    );
  }
}

It would be best if the return from the detail page opens the Searchbar page with the default content and the closed searchbar ...

Discriminative answered 20/11, 2019 at 5:30 Comment(0)
N
1
Scaffold(
        appBar: AppBar(
          backgroundColor: Color.fromRGBO(93, 25, 72, 1),
          toolbarHeight: 60.0,
          title: TextField(
            cursorColor: Colors.white,
            decoration: InputDecoration(
                hintText: " Search...",
                border: InputBorder.none,
                suffixIcon: IconButton(
                  icon: Icon(Icons.search),
                  color: Color.fromRGBO(93, 25, 72, 1),
                  onPressed: () {},
                )),
            style: TextStyle(color: Colors.white, fontSize: 15.0),
          ),
        ),
);
Nedranedrah answered 2/7, 2021 at 14:21 Comment(1)
While this code might answer the OP's question, you could make your answer much better by appending an explanation on how your code solves the problemSwihart
B
1

There is a ready to use widget for this:

      appBar: AppBarWithSearchSwitch(
        onChanged: (text) {
          searchText.value = text;
        }, // or use: onSubmitted: (text) => searchText.value = text,
        appBarBuilder: (context) {
          return AppBar(
            title: Text('Example '),
            actions: [
              AppBarSearchButton(), // button to activate search
            ],
Bridgers answered 17/7, 2022 at 20:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.