loader_search_bar 0.0.2+3

  • README.md
  • CHANGELOG.md
  • Example
  • Installing
  • Versions
  • new50

Loader SearchBar

pub package

Flutter widget integrating search field feature into app bar, allowing to receive query change callbacks and automatically load new data set into ListView. It replaces standard AppBar widget and needs to be placed underneath Scaffold element in the widget tree to work properly.

Loader SearchBar demo

Getting started

To start using SearchBar insert it in place of an AppBar element in the Scaffold widget. Regardless of the use case, defaultAppBar named argument has to be specified, which basically is a widget that will be displayed whenever SearchBar is not in activated state:

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

Optional attributes

  • searchHint - hint string being displayed until user inputs any text
  • iconified - boolean value indicating way of representing non-activated SearchBar:
    • true if widget should be showed as an action item in defaultAppBar
    • false if widget should be merged with defaultAppBar (only leading icon of the default widget and search input field are displayed in such case)
  • autofocus - boolean value determining if search text field should get focus whenever it becomes visible
  • attrs - SearchBarAttrs class instance allowing to specify part of exact values used during widget building (e.g. search bar colors, text size, border radius)
  • onActivatedChanged - callback function receiving widget's current state as a boolean value; triggered whenever user begins or cancels/ends search action

Query callbacks

To get notified about user input specify onQueryChanged and/or onQuerySubmitted callback functions that receive current query string as an argument:

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

QuerySetLoader

By passing QuerySetLoader object as an argument one can additionally benefit from search results being automatically built as ListView widget whenever search query changes:

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

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

Widget _buildItemWidget(Item item) { ... }
  • querySetCall - function transforming search query into list of items being then rendered in ListView (required)
  • itemBuilder - function creating Widget object for received item, called during ListView building for each element of the results set (required)
  • loadOnEachChange - boolean value indicating whether querySetCall should be triggered on each query change; if false query set is loaded once user submits query
  • animateChanges - determines whether ListView's insert and remove operations should be animated

Contributions

Any kind of contribution to the project is welcomed.
Feel free to request new features, report encountered bugs or pull request changes you've made.
To do so, make use of Pull requests and Issues tabs.

[0.0.2] - 03/06/2018

  • Update documentation
  • Add dart docs

[0.0.1] - 02/06/2018

  • Implement search bar widget
  • Support query callbacks
  • Support query set loader
  • Include search bar examples

example/lib/main.dart

import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:loader_search_bar/loader_search_bar.dart';

enum Example { CALLBACK, LOADER }

void main() => _runExample(Example.LOADER);

void _runExample(Example example) {
  runApp(MaterialApp(
    home: example == Example.CALLBACK
        ? CallbackSearchBarPage()
        : LoaderSearchBarPage(),
    debugShowCheckedModeBanner: false,
  ));
}

class CallbackSearchBarPage extends StatefulWidget {
  @override
  CallbackSearchBarPageState createState() => CallbackSearchBarPageState();
}

class CallbackSearchBarPageState extends State<CallbackSearchBarPage> {
  String _queryText = '';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: SearchBar(
        iconified: false,
        defaultAppBar: _appBar,
        onQueryChanged: (query) => _onQueryChanged(context, query),
        onQuerySubmitted: (query) => _onQuerySubmitted(context, query),
      ),
      body: _body,
      drawer: _drawer,
    );
  }

  AppBar get _appBar => AppBar(
        leading: _leadingButton,
        title: Text('Search bar example'),
      );

  Container get _body {
    return Container(
      color: Colors.black12,
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          Text('Callback example', style: TextStyle(fontSize: 18.0)),
          Container(margin: EdgeInsets.only(top: 8.0)),
          Text(_queryText, style: TextStyle(fontSize: 18.0)),
        ],
      ),
    );
  }

  _onQueryChanged(BuildContext context, String query) {
    setState(() => _queryText = 'Query changed: $query');
  }

  _onQuerySubmitted(BuildContext context, String query) {
    setState(() => _queryText = 'Query submitted!');
  }
}

class LoaderSearchBarPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: SearchBar(
        iconified: true,
        defaultAppBar: _appBar,
        searchHint: 'Search persons...',
        loader: QuerySetLoader<Person>(
          querySetCall: Person.filterPersonsByQuery,
          itemBuilder: Person.buildPersonRow,
          loadOnEachChange: true,
          animateChanges: true,
        ),
      ),
      body: _body,
      drawer: _drawer,
    );
  }

  AppBar get _appBar => AppBar(
        leading: _leadingButton,
        title: Text('Loader example'),
      );

  Widget get _body => Container(
        color: Colors.black12,
        child: Center(
          child: Text('Iconified bar page', style: TextStyle(fontSize: 18.0)),
        ),
      );
}

Widget get _leadingButton => InkWell(
      borderRadius: BorderRadius.circular(16.0),
      child: Container(
        margin: EdgeInsets.all(12.0),
        child: Icon(Icons.menu, color: Colors.black, size: 24.0),
      ),
    );

Drawer get _drawer => Drawer();

class Person {
  const Person(this.name, this.uri, this.address, this.hasPhone, this.hasEmail);

  final String name;
  final String uri;
  final String address;
  final bool hasPhone;
  final bool hasEmail;

  static const _imageSize = 48.0;
  static const _progressBarSize = 24.0;
  static const _tileDividerMargin = 72.0;

  static List<Person> filterPersonsByQuery(String query) {
    return persons
        .where(
            (person) => person.name.toLowerCase().contains(query.toLowerCase()))
        .toList();
  }

  static Widget buildPersonRow(Person person) {
    return Container(
      color: Colors.white,
      child: Column(
        children: [
          _buildPersonTile(person),
          _buildTileDivider(),
        ],
      ),
    );
  }

  static Widget _buildPersonTile(Person person) {
    return ListTile(
      leading: _buildPersonImage(person),
      title: Text(person.name),
      subtitle: Text(person.address),
      trailing: _buildTrailingIcons(person),
    );
  }

  static Widget _buildPersonImage(Person person) {
    return Container(
      width: _imageSize,
      height: _imageSize,
      child: Stack(
        children: [
          _buildImageProgressBar(),
          _buildNetworkImage(person.uri),
        ],
      ),
    );
  }

  static Widget _buildImageProgressBar() {
    return Center(
      child: Container(
          width: _progressBarSize,
          height: _progressBarSize,
          child: CircularProgressIndicator(
            strokeWidth: 2.0,
          )),
    );
  }

  static Widget _buildNetworkImage(String uri) {
    return Center(
      child: ClipOval(
        child: new FadeInImage.memoryNetwork(
          placeholder: transparentImage,
          image: uri,
        ),
      ),
    );
  }

  static Widget _buildTrailingIcons(Person person) {
    return Row(
      children: [
        _buildTrailingIcon(Icons.phone, person.hasPhone),
        _buildTrailingIcon(Icons.mail_outline, person.hasEmail),
        _buildTrailingIcon(Icons.more_vert, true, padding: 0.0),
      ],
    );
  }

  static Widget _buildTrailingIcon(IconData icon, bool enabled,
      {double padding = 4.0}) {
    return Padding(
      padding: EdgeInsets.symmetric(horizontal: padding),
      child: Icon(
        icon,
        color: enabled ? Colors.black54 : Colors.black26,
      ),
    );
  }

  static Widget _buildTileDivider() {
    return Container(
      margin: EdgeInsets.only(left: _tileDividerMargin),
      height: 1.0,
      color: Colors.black12,
    );
  }

  static const List<Person> persons = [
    Person('Derek Robertson', 'https://randomuser.me/api/portraits/men/4.jpg',
        '8397 California St', true, false),
    Person('Ethel Mills', 'https://randomuser.me/api/portraits/women/60.jpg',
        '5050 Dogwood Ave', true, true),
    Person('Aiden Cruz', 'https://randomuser.me/api/portraits/men/87.jpg',
        '8866 W Gray St', false, false),
    Person('Earl Ray', 'https://randomuser.me/api/portraits/men/40.jpg',
        '3220 Central St', false, true),
    Person('Arnold Bailey', 'https://randomuser.me/api/portraits/men/92.jpg',
        '1809 Abby Park St', true, true),
    Person('Evelyn Oliver', 'https://randomuser.me/api/portraits/women/90.jpg',
        '3220 Central St', true, false),
    Person('Wesley Byrd', 'https://randomuser.me/api/portraits/men/61.jpg',
        '3603 W Tropical Pkwy', true, true),
    Person('Andre Stewart', 'https://randomuser.me/api/portraits/men/73.jpg',
        '5931 Railroad St', false, true),
    Person('Denise Rose', 'https://randomuser.me/api/portraits/women/95.jpg',
        '5928 Cherry St', false, false),
    Person('Jane Morrison', 'https://randomuser.me/api/portraits/women/4.jpg',
        '3499 Perfect Day Ave', true, true),
  ];
}

final transparentImage = Uint8List.fromList(<int>[
  0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49,
  0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x06,
  0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4, 0x89, 0x00, 0x00, 0x00, 0x0A, 0x49, 0x44,
  0x41, 0x54, 0x78, 0x9C, 0x63, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00, 0x01, 0x0D,
  0x0A, 0x2D, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE
]);

Use this package as a library

1. Depend on it

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


dependencies:
  loader_search_bar: "^0.0.2+3"

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter packages get

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

3. Import it

Now in your Dart code, you can use:


      import 'package:loader_search_bar/loader_search_bar.dart';
  
Version Uploaded Documentation Archive
0.0.2+3 Jun 3, 2018 Go to the documentation of loader_search_bar 0.0.2+3 Download loader_search_bar 0.0.2+3 archive
0.0.2+2 Jun 3, 2018 Go to the documentation of loader_search_bar 0.0.2+2 Download loader_search_bar 0.0.2+2 archive
0.0.2+1 Jun 3, 2018 Go to the documentation of loader_search_bar 0.0.2+1 Download loader_search_bar 0.0.2+1 archive
0.0.2 Jun 2, 2018 Go to the documentation of loader_search_bar 0.0.2 Download loader_search_bar 0.0.2 archive
0.0.1 Jun 2, 2018 Go to the documentation of loader_search_bar 0.0.1 Download loader_search_bar 0.0.1 archive

Analysis

We analyzed this package on Jun 19, 2018, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.0.0-dev.63.0
  • pana: 0.11.3
  • Flutter: 0.5.4

Scores

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

Platforms

Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

Suggestions

  • The description is too short.

    Add more detail about the package, what it does and what is its target use case. Try to write at least 60 characters.

  • Package is pre-v1 release.

    While there is nothing inherently wrong with versions of 0.*.*, it usually means that the author is still experimenting with the general direction API.

  • Fix analysis and formatting issues.

    Analysis or formatting checks reported 1 hint.

    Run flutter format to format lib/src/SearchBarBuilder.dart.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=1.19.0 <2.0.0
flutter 0.0.0
Transitive dependencies
collection 1.14.6 1.14.10
meta 1.1.5
sky_engine 0.0.99
typed_data 1.1.5
vector_math 2.0.6 2.0.7
Dev dependencies
flutter_test