Posted in

How to make Search Bar in Flutter

A search bar is one of the most essential UI components in modern applications. It’s the user’s primary tool for finding content quickly and efficiently. A well-implemented search bar can dramatically improve user experience, while a poor one can lead to frustration.

In this guide, we’ll cover everything you need to know to build a powerful and responsive search bar in Flutter. We’ll start with a simple TextField, move on to filtering a list of data in real-time, and finally, explore Flutter’s built-in SearchDelegate for a more advanced, full-screen search experience.

The Foundation: Building a Search UI with TextField

At its core, a search bar is just a styled TextField widget. We can place it directly in the AppBar for easy access. Let’s start by creating a visually appealing search input field.

The key is the decoration property of the TextField, which allows us to customize its appearance with hints, icons, and borders.

Dart

import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Search'),
        // The search area here
        bottom: PreferredSize(
          preferredSize: const Size.fromHeight(60.0),
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: TextField(
              decoration: InputDecoration(
                hintText: 'Search for something...',
                // Add a clear button to the search bar
                suffixIcon: IconButton(
                  icon: const Icon(Icons.clear),
                  onPressed: () => print("Clear"),
                ),
                // Add a search icon to the search bar
                prefixIcon: IconButton(
                  icon: const Icon(Icons.search),
                  onPressed: () {
                    // Perform the search here
                  },
                ),
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.circular(20.0),
                ),
              ),
            ),
          ),
        ),
      ),
      body: const Center(
        child: Text('Your content goes here'),
      ),
    );
  }
}
Dart

In this snippet, we use a TextField inside the bottom property of the AppBar. We’ve added:

  • hintText: To guide the user.
  • prefixIcon: The classic search magnifying glass.
  • suffixIcon: A button to clear the input.
  • border: A rounded border to give it a modern look.

Making It Functional: Filtering a List

A search bar isn’t useful until it can filter data. Let’s create a stateful widget that filters a list of strings based on the user’s input.

We’ll need two lists: one to hold all the original items and another to hold the filtered items that match the search query. We’ll use a TextEditingController to listen to changes in the search field.

Dart

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: SearchPage(),
    );
  }
}

class SearchPage extends StatefulWidget {
  const SearchPage({super.key});

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

class _SearchPageState extends State<SearchPage> {
  final TextEditingController _searchController = TextEditingController();
  List<String> _allItems = [
    'Apple', 'Banana', 'Cherry', 'Date', 'Elderberry',
    'Fig', 'Grape', 'Honeydew', 'Kiwi', 'Lemon'
  ];
  List<String> _filteredItems = [];

  @override
  void initState() {
    super.initState();
    _filteredItems = _allItems;
    _searchController.addListener(_filterItems);
  }

  void _filterItems() {
    final query = _searchController.text.toLowerCase();
    setState(() {
      _filteredItems = _allItems.where((item) {
        return item.toLowerCase().contains(query);
      }).toList();
    });
  }

  @override
  void dispose() {
    _searchController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: TextField(
          controller: _searchController,
          style: const TextStyle(color: Colors.white),
          cursorColor: Colors.white,
          decoration: const InputDecoration(
            hintText: 'Search...',
            hintStyle: TextStyle(color: Colors.white54),
            border: InputBorder.none,
          ),
        ),
      ),
      body: ListView.builder(
        itemCount: _filteredItems.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(_filteredItems[index]),
          );
        },
      ),
    );
  }
}
Dart

How It Works:

  1. initState: We initialize _filteredItems with all items and add a listener to our _searchController.
  2. _filterItems: This function is called every time the text in the search bar changes. It filters _allItems based on whether an item contains the search query (converted to lowercase for case-insensitive matching).
  3. setState: We call setState to rebuild the UI with the _filteredItems list, updating the ListView in real-time.
  4. dispose: It’s crucial to dispose of the TextEditingController to prevent memory leaks.

The Professional Approach: Using SearchDelegate

For a more robust and conventional search experience, Flutter provides the SearchDelegate class. It’s designed to manage a dedicated search screen that overlays your current UI, complete with animations and platform-adaptive back buttons.

Using SearchDelegate is the recommended approach for a polished search feature.

Step 1: Create a Custom Search Delegate

First, create a class that extends SearchDelegate. You’ll need to override four key methods:

Dart

import 'package:flutter/material.dart';

class CustomSearchDelegate extends SearchDelegate {
  // Dummy list
  final List<String> searchTerms = [
    'Apple', 'Banana', 'Cherry', 'Date', 'Elderberry',
    'Fig', 'Grape', 'Honeydew', 'Kiwi', 'Lemon'
  ];

  // To clear the search text
  @override
  List<Widget>? buildActions(BuildContext context) {
    return [
      IconButton(
        icon: const Icon(Icons.clear),
        onPressed: () {
          query = '';
        },
      ),
    ];
  }

  // To exit the search screen
  @override
  Widget? buildLeading(BuildContext context) {
    return IconButton(
      icon: const Icon(Icons.arrow_back),
      onPressed: () {
        close(context, null);
      },
    );
  }

  // To show results based on the search query
  @override
  Widget buildResults(BuildContext context) {
    List<String> matchQuery = [];
    for (var fruit in searchTerms) {
      if (fruit.toLowerCase().contains(query.toLowerCase())) {
        matchQuery.add(fruit);
      }
    }
    return ListView.builder(
      itemCount: matchQuery.length,
      itemBuilder: (context, index) {
        var result = matchQuery[index];
        return ListTile(
          title: Text(result),
        );
      },
    );
  }

  // To show suggestions while the user is typing
  @override
  Widget buildSuggestions(BuildContext context) {
    List<String> matchQuery = [];
    for (var fruit in searchTerms) {
      if (fruit.toLowerCase().contains(query.toLowerCase())) {
        matchQuery.add(fruit);
      }
    }
    return ListView.builder(
      itemCount: matchQuery.length,
      itemBuilder: (context, index) {
        var result = matchQuery[index];
        return ListTile(
          title: Text(result),
          onTap: () {
            query = result;
            showResults(context);
          },
        );
      },
    );
  }
}
Dart
  • buildActions: Defines actions for the AppBar (e.g., a clear button).
  • buildLeading: Defines the leading icon/widget (e.g., a back button to close the search).
  • buildResults: Builds the UI to display after the user submits a search.
  • buildSuggestions: Shows suggestions in real-time as the user types.

Step 2: Launch the Search Delegate

Finally, trigger the search from an IconButton in your main AppBar.

Dart

Scaffold(
  appBar: AppBar(
    title: const Text('Home'),
    actions: [
      IconButton(
        icon: const Icon(Icons.search),
        onPressed: () {
          showSearch(
            context: context,
            delegate: CustomSearchDelegate(),
          );
        },
      )
    ],
  ),
  // ... rest of your scaffold
)
Dart

The showSearch function takes care of pushing a new route and displaying your CustomSearchDelegate.

Building an intuitive search feature is a huge step toward a great user experience. Whether you choose a simple TextField or the more advanced SearchDelegate, the key is to provide fast, relevant results.

Anynew24.com Is A Team Of Passionate Flutter Developers On A Mission To Empower The Community. We Share Our Expertise And Insights Through Comprehensive Guides, Tutorials, And Resources, Making Flutter Mobile App Development Accessible And Enjoyable For Everyone.

Leave a Reply