Newby Coder header banner

Flutter Searchable Dropdown

Dropdown with suggestion in Android/iOS using Flutter

A Searchable dropdown provides options which can be selected for an input field which can be used to search and narrow down the options

searchable_dropdown package can be used to implement searchable dropdown in Flutter


Creating new Flutter App

Check Flutter installation to setup Flutter

Use flutter create command to create a Flutter project (here searchable_dropdown_app) :

flutter create searchable_dropdown_app

Dependency

Usage

Import
import 'package:searchable_dropdown/searchable_dropdown.dart';

Widget that opens a dialog or a menu to let a user select a single choice from suggestions based on search :

SearchableDropdown({
        Key key,
        @required List<DropdownMenuItem<T>> items,
        @required Function onChanged,
        T value,
        dynamic searchHint,
        dynamic hint,
        dynamic icon = const Icon(Icons.arrow_drop_down),
        dynamic label,
        bool isCaseSensitiveSearch = false,
        bool readOnly = false,
        Function searchFn,
        TextInputType keyboardType = TextInputType.text,
        Function displayItem,
    }
)

There are more styling and functional properties mentioned in its Github repo

App code

Following app code implements two SearchableDropdown widgets, one using local data and other using data from server to provide options for selection

A selectedValueMap map is used to store selected value from both dropdowns

searchable_dropdown_app/lib/main.dart
import 'package:flutter/material.dart';
import 'package:searchable_dropdown/searchable_dropdown.dart';
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;


void main() => runApp(SearchableDropdownApp());

class SearchableDropdownApp extends StatefulWidget {
  @override
  _AppState createState() => _AppState();
}

List<String> localData = ['One' ,'Two' ,'Three' ,'Four' ,'Five' ,'Six' ,'Seven' ,'Eight' ,'Nine' ,'Ten' ,];

class _AppState extends State<SearchableDropdownApp> {
  Map<String, String> selectedValueMap = Map();

  @override
  void initState() {
    selectedValueMap["local"] = null;
    selectedValueMap["server"] = null;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          automaticallyImplyLeading: false,
          title: const Text('Searchable Dropdown Example App'),
        ),
        body: new SingleChildScrollView(
          child: Container(
            height: 571,
            width: double.infinity,
            color: Colors.white.withOpacity(0.4),
            child: Container(
              padding: EdgeInsets.only(left: 10),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  new Container(
                    child: new Text(
                      'Dropdown with local data : ',
                      style: new TextStyle(
                        fontSize: 18,
                        fontWeight: FontWeight.bold
                      ),
                    )
                  ),
                  // use local data for providing options and store selected value to the key "local"
                  getSearchableDropdown(localData, "local"),
                  new Container(
                    child: new Text(
                      'server data : ',
                      style: new TextStyle(
                        fontSize: 18,
                        fontWeight: FontWeight.bold
                      ),
                    )
                  ),
                  FutureBuilder<List>(
                    // get data from server and return a list of mapped 'name' fields
                    future: getServerData(), //sets getServerData method as the expected Future
                    builder: (context, snapshot) {
                      if (snapshot.hasData) { //checks if response returned valid data
                        // use mapped 'name' fields for providing options and store selected value to the key "server"
                        return getSearchableDropdown(snapshot.data, "server");
                      }
                      else if (snapshot.hasError) { //checks if the response threw error
                        return Text("${snapshot.error}");
                      }
                      return CircularProgressIndicator();
                    },
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }

  Widget getSearchableDropdown(List<String> listData, mapKey) {
    List<DropdownMenuItem> items = [];
    for(int i=0; i < listData.length; i++) {
      items.add(new DropdownMenuItem(
          child: new Text(
            listData[i],
          ),
          value: listData[i],
        )
      );
    }
    return new SearchableDropdown(
      items: items,
      value: selectedValueMap[mapKey],
      isCaseSensitiveSearch: false,
      hint: new Text(
        'Select One'
      ),
      searchHint: new Text(
        'Select One',
        style: new TextStyle(
            fontSize: 20
        ),
      ),
      onChanged: (value) {
        setState(() {
          selectedValueMap[mapKey] = value;
        });
      },
    );
  }

  Future<List> getServerData() async {
    String url = 'https://restcountries.eu/rest/v2/all';
//    String url = 'http://192.168.43.34:3000/numbers';
    final response = await http.get(url, headers: {"Accept": "application/json"});

    if (response.statusCode == 200) {
      print(response.body);
      List<dynamic> responseBody = json.decode(response.body);
      List<String> countries = new List();
      for(int i=0; i < responseBody.length; i++) {
        countries.add(responseBody[i]['name']);
      }
      return countries;
    }
    else {
      print("error from server : $response");
      throw Exception('Failed to load post');
    }
  }
}

Run instructions

Ensure a supported device is connected or emulator/simulator is started

Go to project directory

Use flutter run command to run

flutter run

It builds and runs app on an available android/ios device


Screenshot/Screencast

Android

cl-flutter-searchable-dropdown

iOS

cm_flutter_searchable_dropdown_as1cm_flutter_searchable_dropdown_as2cm_flutter_searchable_dropdown_as3

Multiple selection

Check Github repo for usage and example of multiple selection

Image from Github repo