search_widget 1.0.0

  • Readme
  • Changelog
  • Example
  • Installing
  • 95

Search Widget Cirrus CI - Base Branch Build Status GitHub stars Twitter Follow GitHub last commit Website shields.io Open Source Love style: effective dart

This Flutter package provides a Search Widget for selecting an option from a data list. Provides filtering of items based on the search text.

PieChart

💻 Installation #

In the dependencies: section of your pubspec.yaml, add the following line:

Version

dependencies:
  search_widget: <latest version>

❔ Usage #

Import this class #

import 'package:search_widget/search_widget.dart';

Add Search Widget #

  • Accepts data list as input
  • Option for getting selected item. Returns selected item or null if item is deleted
onItemSelected: (item) {
    //Do whatever you would like
    setState(() {
       _selectedItem = item;
    });
 },
  • Option for pop list item builder. This basically returns a widget to show as list item in popup
popupListItemBuilder: (LeaderBoard item) {
   return PopupListItem(item);
 }
  • Option for filtering data list based on search query
queryBuilder: (String query, List<LeaderBoard> list) {
   return list.where((LeaderBoard item) => item.username.toLowerCase().contains(query.toLowerCase())).toList();
 }
  • Option provided for selected list item builder which enables when a user selects an item from pop up list
selectedItemBuilder: (LeaderBoard selectedItem, deleteSelectedItem) {
   return SelectedItem(selectedItem,deleteSelectedItem);
 }
  • Option for providing custom TextField. Accepts TextEditingController and FocusNode as parameter
textFieldBuilder: (TextEditingController controller, FocusNode focusNode) {
    return TextField(
        controller: controller,
        focusNode: focusNode,
        //... Other customizations here
       );
  },

Full Implementation #

SearchWidget<LeaderBoard>(
   dataList: list,
   hideSearchBoxWhenItemSelected: false,
   listContainerHeight: MediaQuery.of(context).size.height / 4,
   queryBuilder: (String query, List<LeaderBoard> list) {
     return list.where((LeaderBoard item) => item.username.toLowerCase().contains(query.toLowerCase())).toList();
   },
   popupListItemBuilder: (LeaderBoard item) {
     return PopupListItemWidget(item);
   },
   selectedItemBuilder: (LeaderBoard selectedItem, VoidCallback deleteSelectedItem) {
     return SelectedItemWidget(selectedItem, deleteSelectedItem);
   },
   // widget customization
   noItemsFoundWidget: NoItemsFound(),
   textFieldBuilder: (TextEditingController controller, FocusNode focusNode) {
     return MyTextField(controller, focusNode);
   },
 )

Key Highlights #

  • Adaptive Popup Position to prevent popup getting hidden behind keyboard

PieChart PieChart

  • Popup to scroll with scroll gesture if this widget is used inside ScrollView
PieChart

TODO #

  • [X] Give support for onItemSelected method to return selected item(s) directly
  • [ ] Add support for selecting multiple items
  • [ ] Add visibility bool to show selected item widget

⭐ My Flutter Packages #

  • pie_chart GitHub stars Flutter Pie Chart with cool animation.
  • avatar_glow GitHub stars Flutter Avatar Glow Widget with glowing animation.
  • json_table GitHub stars Create Flutter Json Table from json map directly.
  • animating_location_pin GitHub stars Flutter Animating Location Pin Widget providing Animating Location Pin Widget which can be used while fetching device location.

⭐ My Flutter Apps #

👍 Contribution #

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -m 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

[1.0.0]

  • Fix #3 Add onItemSelected method for getting selected item
  • Fix #4 The method 'markNeedsBuild' was called on null. Thanks @jatempa for PR #6
  • Fix #5 Update keyboard_visibility dependency

[0.2.0]

Merged #

Added #

  • Add TextField builder optional parameter
  • Update Example with more cleanup code
  • Add NoItemsWidget as optional parameter

[0.1.0] - Initial Release

example/lib/main.dart

import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:search_widget/search_widget.dart';

// Sets a platform override for desktop to avoid exceptions. See
// https://flutter.dev/desktop#target-platform-override for more info.
void enablePlatformOverrideForDesktop() {
  if (!kIsWeb && (Platform.isMacOS || Platform.isWindows || Platform.isLinux)) {
    debugDefaultTargetPlatformOverride = TargetPlatform.fuchsia;
  }
}

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Search Widget',
      theme: ThemeData(
        primarySwatch: Colors.blueGrey,
      ),
      debugShowCheckedModeBanner: false,
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  List<LeaderBoard> list = <LeaderBoard>[
    LeaderBoard("Flutter", 54),
    LeaderBoard("React", 22.5),
    LeaderBoard("Ionic", 24.7),
    LeaderBoard("Xamarin", 22.1),
  ];

  LeaderBoard _selectedItem;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Search Widget"),
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.symmetric(vertical: 16),
        child: Column(
          children: <Widget>[
            const SizedBox(
              height: 16,
            ),
            SearchWidget<LeaderBoard>(
              dataList: list,
              hideSearchBoxWhenItemSelected: false,
              listContainerHeight: MediaQuery.of(context).size.height / 4,
              queryBuilder: (query, list) {
                return list
                    .where((item) => item.username
                        .toLowerCase()
                        .contains(query.toLowerCase()))
                    .toList();
              },
              popupListItemBuilder: (item) {
                return PopupListItemWidget(item);
              },
              selectedItemBuilder: (selectedItem, deleteSelectedItem) {
                return SelectedItemWidget(selectedItem, deleteSelectedItem);
              },
              // widget customization
              noItemsFoundWidget: NoItemsFound(),
              textFieldBuilder: (controller, focusNode) {
                return MyTextField(controller, focusNode);
              },
              onItemSelected: (item) {
                setState(() {
                  _selectedItem = item;
                });
              },
            ),
            const SizedBox(
              height: 32,
            ),
            Text(
              "${_selectedItem != null ? _selectedItem.username : ""
                  "No item selected"}",
            ),
          ],
        ),
      ),
    );
  }
}

class LeaderBoard {
  LeaderBoard(this.username, this.score);

  final String username;
  final double score;
}

class SelectedItemWidget extends StatelessWidget {
  const SelectedItemWidget(this.selectedItem, this.deleteSelectedItem);

  final LeaderBoard selectedItem;
  final VoidCallback deleteSelectedItem;

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.symmetric(
        vertical: 2,
        horizontal: 4,
      ),
      child: Row(
        children: <Widget>[
          Expanded(
            child: Padding(
              padding: const EdgeInsets.only(
                left: 16,
                right: 16,
                top: 8,
                bottom: 8,
              ),
              child: Text(
                selectedItem.username,
                style: const TextStyle(fontSize: 14),
              ),
            ),
          ),
          IconButton(
            icon: Icon(Icons.delete_outline, size: 22),
            color: Colors.grey[700],
            onPressed: deleteSelectedItem,
          ),
        ],
      ),
    );
  }
}

class MyTextField extends StatelessWidget {
  const MyTextField(this.controller, this.focusNode);

  final TextEditingController controller;
  final FocusNode focusNode;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
      child: TextField(
        controller: controller,
        focusNode: focusNode,
        style: TextStyle(fontSize: 16, color: Colors.grey[600]),
        decoration: InputDecoration(
          enabledBorder: const OutlineInputBorder(
            borderSide: BorderSide(
              color: Color(0x4437474F),
            ),
          ),
          focusedBorder: OutlineInputBorder(
            borderSide: BorderSide(color: Theme.of(context).primaryColor),
          ),
          suffixIcon: Icon(Icons.search),
          border: InputBorder.none,
          hintText: "Search here...",
          contentPadding: const EdgeInsets.only(
            left: 16,
            right: 20,
            top: 14,
            bottom: 14,
          ),
        ),
      ),
    );
  }
}

class NoItemsFound extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: <Widget>[
        Icon(
          Icons.folder_open,
          size: 24,
          color: Colors.grey[900].withOpacity(0.7),
        ),
        const SizedBox(width: 10),
        Text(
          "No Items Found",
          style: TextStyle(
            fontSize: 16,
            color: Colors.grey[900].withOpacity(0.7),
          ),
        ),
      ],
    );
  }
}

class PopupListItemWidget extends StatelessWidget {
  const PopupListItemWidget(this.item);

  final LeaderBoard item;

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(12),
      child: Text(
        item.username,
        style: const TextStyle(fontSize: 16),
      ),
    );
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  search_widget: ^1.0.0

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:search_widget/search_widget.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
90
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
95
Learn more about scoring.

We analyzed this package on Dec 10, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.7.0
  • pana: 0.13.1+4
  • Flutter: 1.12.13+hotfix.4

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.2.2 <3.0.0
flutter 0.0.0
keyboard_visibility ^0.5.6 0.5.6
Transitive dependencies
collection 1.14.11 1.14.12
meta 1.1.8
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test