Advertisement
DVS_studio

searchBar.dart

May 22nd, 2018
196
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Dart 6.91 KB | None | 0 0
  1. import 'dart:async';
  2.  
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter/services.dart';
  5. import 'package:meta/meta.dart';
  6.  
  7. typedef AppBar AppBarCallback(BuildContext context);
  8. typedef void TextFieldSubmitCallback(String value);
  9. typedef void TextFieldClearCallback();
  10. typedef void SetStateCallback(void fn());
  11.  
  12. class SearchBar {
  13.   /// Whether the search should take place "in the existing search bar", meaning whether it has the same background or a flipped one. Defaults to true.
  14.   final bool inBar;
  15.  
  16.   /// Whether the back button should be colored, if this is false the back button will be Colors.grey.shade400
  17.   final bool colorBackButton;
  18.  
  19.   /// Whether or not the search bar should close on submit. Defaults to true.
  20.   final bool closeOnSubmit;
  21.  
  22.   /// Whether the text field should be cleared when it is submitted
  23.   final bool clearOnSubmit;
  24.  
  25.   /// A callback which should return an AppBar that is displayed until search is started. One of the actions in this AppBar should be a search button which you obtain from SearchBar.getSearchAction(). This will be called every time search is ended, etc. (like a build method on a widget)
  26.   final AppBarCallback buildDefaultAppBar;
  27.  
  28.   /// A void callback which takes a string as an argument, this is fired every time the search is submitted. Do what you want with the result.
  29.   final TextFieldSubmitCallback onSubmitted;
  30.  
  31.   final TextFieldSubmitCallback onType;
  32.  
  33.   final TextFieldClearCallback onClear;
  34.  
  35.   /// Since this should be inside of a State class, just pass setState to this.
  36.   final SetStateCallback setState;
  37.  
  38.   /// Whether or not the search bar should add a clear input button, defaults to true.
  39.   final bool showClearButton;
  40.  
  41.   /// What the hintText on the search bar should be. Defaults to 'Search'.
  42.   String hintText;
  43.  
  44.   /// The controller to be used in the textField.
  45.   TextEditingController controller;
  46.  
  47.   /// Whether search is currently active.
  48.   bool _isSearching = false;
  49.  
  50.   /// Whether the clear button should be active (fully colored) or inactive (greyed out)
  51.   bool _clearActive = false;
  52.  
  53.   /// The last built default AppBar used for colors and such.
  54.   AppBar _defaultAppBar;
  55.  
  56.  
  57.   SearchBar({@required this.setState,
  58.     @required this.buildDefaultAppBar,
  59.     this.onSubmitted,
  60.     this.onType,
  61.     this.onClear,
  62.     this.controller,
  63.     this.hintText = 'Search',
  64.     this.inBar = true,
  65.     this.colorBackButton = true,
  66.     this.closeOnSubmit = true,
  67.     this.clearOnSubmit = true,
  68.     this.showClearButton = true}) {
  69.     if (this.controller == null) {
  70.       this.controller = new TextEditingController();
  71.     }
  72.  
  73.     // Don't waste resources on listeners for the text controller if the dev
  74.     // doesn't want a clear button anyways in the search bar
  75.     if (!this.showClearButton) {
  76.       return;
  77.     }
  78.  
  79.     this.controller.addListener(() {
  80.       if (this.controller.text.isEmpty) {
  81.         // If clear is already disabled, don't disable it
  82.         if (_clearActive) {
  83.           setState(() {
  84.             _clearActive = false;
  85.           });
  86.         }
  87.         onClear();
  88.         return;
  89.       }
  90.       onType(this.controller.text);
  91.       // If clear is already enabled, don't enable it
  92.       if (!_clearActive) {
  93.         setState(() {
  94.           _clearActive = true;
  95.         });
  96.       }
  97.     });
  98.   }
  99.  
  100.   /// Whether search is currently active.
  101.   bool get isSearching => _isSearching;
  102.  
  103.   /// Initializes the search bar.
  104.   ///
  105.   /// This adds a new route that listens for onRemove (and stops the search when that happens), and then calls [setState] to rebuild and start the search.
  106.   void beginSearch(context) {
  107.     ModalRoute.of(context).addLocalHistoryEntry(new LocalHistoryEntry(onRemove: () {
  108.       setState(() {
  109.         controller.text = "";
  110.         onType(null);
  111.         _isSearching = false;
  112.       });
  113.     }));
  114.  
  115.     setState(() {
  116.       _isSearching = true;
  117.     });
  118.   }
  119.  
  120.   /// Builds, saves and returns the default app bar.
  121.   ///
  122.   /// This calls the [buildDefaultAppBar] provided in the constructor, and saves it to [_defaultAppBar].
  123.   AppBar buildAppBar(BuildContext context) {
  124.     _defaultAppBar = buildDefaultAppBar(context);
  125.  
  126.     return _defaultAppBar;
  127.   }
  128.  
  129.   /// Builds the search bar!
  130.   ///
  131.   /// The leading will always be a back button.
  132.   /// backgroundColor is determined by the value of inBar
  133.   /// title is always a [TextField] with the key 'SearchBarTextField', and various text stylings based on [inBar]. This is also where [onSubmitted] has its listener registered.
  134.   ///
  135.   AppBar buildSearchBar(BuildContext context) {
  136.     ThemeData theme = Theme.of(context);
  137.  
  138.     Color barColor = inBar ? _defaultAppBar.backgroundColor : theme.canvasColor;
  139.  
  140.     // Don't provide a color (make it white) if it's in the bar, otherwise color it or set it to grey.
  141.     Color buttonColor = inBar
  142.         ? null
  143.         : (colorBackButton
  144.         ? _defaultAppBar.backgroundColor ?? theme.primaryColor ?? Colors.grey.shade400
  145.         : Colors.grey.shade400);
  146.     Color buttonDisabledColor = inBar ? new Color.fromRGBO(255, 255, 255, 0.25) : Colors.grey.shade300;
  147.  
  148.     Color textColor = inBar ? Colors.white70 : Colors.black54;
  149.  
  150.     return new AppBar(
  151.       leading: new BackButton(color: buttonColor),
  152.       backgroundColor: barColor,
  153.       title: new Directionality(
  154.         textDirection: Directionality.of(context),
  155.         child: new TextFormField(
  156.           style: new TextStyle(color: textColor, fontSize: 16.0),
  157.           key: new Key('SearchBarTextField'),
  158.           keyboardType: TextInputType.text,
  159.           onSaved: (String val) async {
  160.             if (closeOnSubmit) {
  161.               await Navigator.maybePop(context);
  162.             }
  163.  
  164.             if (clearOnSubmit) {
  165.               controller.clear();
  166.             }
  167.  
  168.             onSubmitted(val);
  169.           },
  170.           autofocus: true,
  171.           controller: controller,
  172.           decoration: new InputDecoration(
  173.               hintText: hintText, hintStyle: new TextStyle(color: textColor, fontSize: 16.0), border: null),
  174.         ),
  175.       ),
  176.       actions: <Widget>[
  177.         !showClearButton
  178.             ? const Text("")
  179.             : new IconButton(
  180.             icon: new Icon(Icons.clear, color: _clearActive ? buttonColor : buttonDisabledColor),
  181.             disabledColor: buttonDisabledColor,
  182.             onPressed: !_clearActive
  183.                 ? null
  184.                 : () {
  185.               controller.clear();
  186.             })
  187.       ],
  188.     );
  189.   }
  190.  
  191.   /// Returns an [IconButton] suitable for an Action
  192.   ///
  193.   /// Put this inside your [buildDefaultAppBar] method!
  194.   IconButton getSearchAction(BuildContext context) {
  195.     return new IconButton(
  196.         icon: new Icon(Icons.search),
  197.         onPressed: () {
  198.           beginSearch(context);
  199.         });
  200.   }
  201.  
  202.   /// Returns an AppBar based on the value of [_isSearching]
  203.   AppBar build(BuildContext context) {
  204.     return _isSearching ? buildSearchBar(context) : buildAppBar(context);
  205.   }
  206.  
  207. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement