diff --git a/example/lib/main.dart b/example/lib/main.dart index 64efdd4d..456226fb 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -22,7 +22,6 @@ import 'package:getflutter/components/tabs/gf_tabs.dart'; import 'package:getflutter/components/tabs/gf_tabBarView.dart'; import 'package:getflutter/types/gf_button_type.dart'; import 'package:getflutter/position/gf_position.dart'; -import 'dart:io'; final List imageList = [ "https://cdn.pixabay.com/photo/2017/12/03/18/04/christmas-balls-2995437_960_720.jpg", @@ -69,7 +68,6 @@ class _MyHomePageState extends State void initState() { super.initState(); tabController = TabController(length: 3, vsync: this); - _searchQuery = new TextEditingController(); } @override @@ -80,102 +78,9 @@ class _MyHomePageState extends State bool switchValue = true; bool showToast = false; - Widget appBarTitle = new Text("UI Kit"); Icon actionIcon = new Icon(Icons.search); - TextEditingController _searchQuery; - bool _isSearching = false; - String searchQuery = "Search query"; - - void _startSearch() { - ModalRoute.of(context) - .addLocalHistoryEntry(new LocalHistoryEntry(onRemove: _stopSearching)); - - setState(() { - _isSearching = true; - }); - } - - void _stopSearching() { - _clearSearchQuery(); - - setState(() { - _isSearching = false; - }); - } - - void _clearSearchQuery() { - setState(() { - _searchQuery.clear(); - updateSearchQuery("Search query"); - }); - } - - Widget _buildTitle(BuildContext context) { - var horizontalTitleAlignment = - Platform.isIOS ? CrossAxisAlignment.center : CrossAxisAlignment.start; - - return new InkWell( - onTap: () => scaffoldKey.currentState.openDrawer(), - child: new Padding( - padding: const EdgeInsets.symmetric(horizontal: 12.0), - child: new Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: horizontalTitleAlignment, - children: [ - const Text('Seach box'), - ], - ), - ), - ); - } - - Widget _buildSearchField() { - return new TextField( - controller: _searchQuery, - autofocus: true, - decoration: const InputDecoration( - hintText: 'Search...', - border: InputBorder.none, - hintStyle: const TextStyle(color: Colors.white30), - ), - style: const TextStyle(color: Colors.white, fontSize: 16.0), - onChanged: updateSearchQuery, - ); - } - - void updateSearchQuery(String newQuery) { - setState(() { - searchQuery = newQuery; - }); - print("search query " + newQuery); - } - - List _buildActions() { - if (_isSearching) { - return [ - new IconButton( - icon: const Icon(Icons.clear), - onPressed: () { - if (_searchQuery == null || _searchQuery.text.isEmpty) { - Navigator.pop(context); - return; - } - _clearSearchQuery(); - }, - ), - ]; - } - - return [ - new IconButton( - icon: const Icon(Icons.search), - onPressed: _startSearch, - ), - ]; - } - @override Widget build(BuildContext context) { return Scaffold( @@ -239,50 +144,32 @@ class _MyHomePageState extends State ], ), ), - appBar: AppBar( - leading: _isSearching ? const BackButton() : null, - title: _isSearching ? _buildSearchField() : _buildTitle(context), - actions: _buildActions(), - ), -// GFAppBar( -//// backgroundColor: Colors.tealAccent, + + appBar: GFAppBar( + backgroundColor: Colors.teal, // centerTitle: true, -//// leading: GFIconButton(icon: Icon(Icons.directions_bus), onPressed: (){}), -// title: appBarTitle, -//// bottom: TabBar( -//// controller: tabController, -//// tabs: [ -//// Tab(icon: Icon(Icons.directions_car)), -//// Tab(icon: Icon(Icons.directions_transit)), -//// Tab(icon: Icon(Icons.directions_bike)), -//// ], -//// ), -// actions: [ -// new IconButton( -// icon: actionIcon, -// onPressed: () { -// setState(() { -// if (this.actionIcon.icon == Icons.search) { -// this.actionIcon = new Icon(Icons.close); -// this.appBarTitle = new TextField( -// style: new TextStyle( -// color: Colors.white, -// ), -// decoration: new InputDecoration( -// prefixIcon: new Icon(Icons.search, color: Colors.white), -// hintText: "Search...", -// hintStyle: new TextStyle(color: Colors.white)), -// ); -// } else { -// this.actionIcon = new Icon(Icons.search); -// this.appBarTitle = new Text("UI Kit"); -// } -// }); -// }, -// ), -// ], -// ), -// backgroundColor: Colors.teal, +// leading: GFIconButton(icon: Icon(Icons.directions_bus), onPressed: (){}), + title: Text("UI Kit"), +// bottom: TabBar( +// controller: tabController, +// tabs: [ +// Tab(icon: Icon(Icons.directions_car)), +// Tab(icon: Icon(Icons.directions_transit)), +// Tab(icon: Icon(Icons.directions_bike)), +// ], +// ), +// searchBar: true, +// searchHintText: "aaaaaaa", +// searchHintStyle: TextStyle(fontSize: 18.0, color: Colors.redAccent), +// searchStyle: TextStyle(fontSize: 10.0, color: Colors.green), +// searchBarColorTheme: Colors.greenAccent, + + actions: [ + GFIconButton(icon: Icon(Icons.access_time), onPressed: () {}), + GFIconButton(icon: Icon(Icons.favorite), onPressed: null), + ], + ), + backgroundColor: Colors.blueGrey, body: // GFTabBarView( // height: 200.0, diff --git a/lib/components/appbar/gf_appbar.dart b/lib/components/appbar/gf_appbar.dart index f0326879..73a6900f 100644 --- a/lib/components/appbar/gf_appbar.dart +++ b/lib/components/appbar/gf_appbar.dart @@ -3,6 +3,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter/material.dart'; +import 'package:getflutter/getflutter.dart'; /// An app bar consists of a toolbar and potentially other widgets, such as a /// [GFTabBar][TabBar] and a [FlexibleSpaceBar]. @@ -41,6 +42,17 @@ class GFAppBar extends StatefulWidget implements PreferredSizeWidget { this.titleSpacing = NavigationToolbar.kMiddleSpacing, this.toolbarOpacity = 1.0, this.bottomOpacity = 1.0, + this.searchBar = false, + this.searchHintText = 'Search...', + this.searchHintStyle = const TextStyle(color: Colors.white, fontSize: 14.0), + this.searchTextStyle = const TextStyle( + color: Colors.white, + ), + this.searchBarColorTheme = Colors.white, + this.searchController, + this.onTap, + this.onChanged, + this.onSubmitted, }) : assert(automaticallyImplyLeading != null), assert(elevation == null || elevation >= 0.0), assert(primary != null), @@ -192,6 +204,67 @@ class GFAppBar extends StatefulWidget implements PreferredSizeWidget { @override final Size preferredSize; + /// If true, displays search bar in the title space + final bool searchBar; + + /// It takes text to displays the search bar hint text + final String searchHintText; + + /// It styles the [searchHintText] + final TextStyle searchHintStyle; + + /// It styles the search text + final TextStyle searchTextStyle; + + /// It defines the search bar icons color + final Color searchBarColorTheme; + + /// {@macro flutter.widgets.editableText.onChanged} + /// + /// See also: + /// + /// * [inputFormatters], which are called before [onChanged] + /// runs and can validate and change ("format") the input value. + /// * [onEditingComplete], [onSubmitted], [onSelectionChanged]: + /// which are more specialized input change notifications. + final ValueChanged onChanged; + + /// {@macro flutter.widgets.editableText.onSubmitted} + /// + /// See also: + /// + /// * [EditableText.onSubmitted] for an example of how to handle moving to + /// the next/previous field when using [TextInputAction.next] and + /// [TextInputAction.previous] for [textInputAction]. + final ValueChanged onSubmitted; + + /// Controls the text being edited. + /// + /// If null, this widget will create its own [TextEditingController]. + final TextEditingController searchController; + + /// {@template flutter.material.textfield.onTap} + /// Called for each distinct tap except for every second tap of a double tap. + /// + /// The text field builds a [GestureDetector] to handle input events like tap, + /// to trigger focus requests, to move the caret, adjust the selection, etc. + /// Handling some of those events by wrapping the text field with a competing + /// GestureDetector is problematic. + /// + /// To unconditionally handle taps, without interfering with the text field's + /// internal gesture detector, provide this callback. + /// + /// If the text field is created with [enabled] false, taps will not be + /// recognized. + /// + /// To be notified when the text field gains or loses the focus, provide a + /// [focusNode] and add a listener to that. + /// + /// To listen to arbitrary pointer events without competing with the + /// text field's internal gesture detector, use a [Listener]. + /// {@endtemplate} + final GestureTapCallback onTap; + bool _getEffectiveCenterTitle(ThemeData theme) { if (centerTitle != null) return centerTitle; assert(theme.platform != null); @@ -221,6 +294,9 @@ class _GFAppBarState extends State { Scaffold.of(context).openEndDrawer(); } + Widget searchBar; + bool showSearchBar = true; + @override Widget build(BuildContext context) { assert(!widget.primary || debugCheckHasMediaQuery(context)); @@ -303,7 +379,7 @@ class _GFAppBarState extends State { overflow: TextOverflow.ellipsis, child: Semantics( namesRoute: namesRoute, - child: _GFAppBarTitleBox(child: title), + child: GFAppBarTitleBar(child: title), header: true, ), ); @@ -332,9 +408,66 @@ class _GFAppBarState extends State { ); } + searchBar = ListTile( + contentPadding: EdgeInsets.zero, + title: TextField( + cursorColor: widget.searchBarColorTheme, + style: widget.searchTextStyle, + decoration: new InputDecoration( + prefixIcon: new Icon( + Icons.search, + color: widget.searchBarColorTheme, + size: 18.0, + ), + hintText: widget.searchHintText, + hintStyle: widget.searchHintStyle, + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide(width: 1, color: widget.searchBarColorTheme), + ), + ), + onTap: widget.onTap, + onChanged: widget.onChanged, + controller: widget.searchController, + onSubmitted: widget.onSubmitted, + ), + trailing: GFIconButton( + icon: Icon( + Icons.close, + color: widget.searchBarColorTheme, + size: 20.0, + ), + type: GFButtonType.transparent, + onPressed: () { + setState(() { + showSearchBar = !showSearchBar; + }); + }, + ), + ); + + if (!showSearchBar) { + searchBar = ListTile( + contentPadding: EdgeInsets.zero, + title: title, + trailing: GFIconButton( + icon: Icon( + Icons.search, + color: widget.searchBarColorTheme, + size: 20.0, + ), + type: GFButtonType.transparent, + onPressed: () { + setState(() { + showSearchBar = !showSearchBar; + }); + }, + ), + ); + } + final Widget toolbar = NavigationToolbar( leading: leading, - middle: title, + middle: widget.searchBar ? searchBar : title, trailing: actions, centerMiddle: widget._getEffectiveCenterTitle(theme), middleSpacing: widget.titleSpacing, @@ -450,27 +583,27 @@ class _ToolbarContainerLayout extends SingleChildLayoutDelegate { // Layout the GFAppBar's title with unconstrained height, vertically // center it within its (NavigationToolbar) parent, and allow the // parent to constrain the title's actual height. -class _GFAppBarTitleBox extends SingleChildRenderObjectWidget { - const _GFAppBarTitleBox({Key key, @required Widget child}) +class GFAppBarTitleBar extends SingleChildRenderObjectWidget { + const GFAppBarTitleBar({Key key, @required Widget child}) : assert(child != null), super(key: key, child: child); @override - _RenderGFAppBarTitleBox createRenderObject(BuildContext context) { - return _RenderGFAppBarTitleBox( + RenderGFAppBarTitleBar createRenderObject(BuildContext context) { + return RenderGFAppBarTitleBar( textDirection: Directionality.of(context), ); } @override void updateRenderObject( - BuildContext context, _RenderGFAppBarTitleBox renderObject) { + BuildContext context, RenderGFAppBarTitleBar renderObject) { renderObject.textDirection = Directionality.of(context); } } -class _RenderGFAppBarTitleBox extends RenderAligningShiftedBox { - _RenderGFAppBarTitleBox({ +class RenderGFAppBarTitleBar extends RenderAligningShiftedBox { + RenderGFAppBarTitleBar({ RenderBox child, TextDirection textDirection, }) : super( diff --git a/lib/components/search_bar/gf_search_bar.dart b/lib/components/search_bar/gf_search_bar.dart index 4ce4e8a1..8b137891 100644 --- a/lib/components/search_bar/gf_search_bar.dart +++ b/lib/components/search_bar/gf_search_bar.dart @@ -1,8 +1 @@ -import 'package:flutter/material.dart'; -class GFSearchBar extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Container(); - } -} diff --git a/lib/components/toggle/gf_toggle.dart b/lib/components/toggle/gf_toggle.dart index afc76c4f..fccc8c1a 100644 --- a/lib/components/toggle/gf_toggle.dart +++ b/lib/components/toggle/gf_toggle.dart @@ -16,7 +16,7 @@ class GFToggle extends StatefulWidget { GFToggle( {Key key, @required this.onChanged, - this.value , + this.value, this.enabledText, this.disabledText, this.enabledTextStyle, @@ -73,7 +73,6 @@ class GFToggle extends StatefulWidget { /// Called when the user toggles the switch on or off. final ValueChanged onChanged; - @override _GFToggleState createState() => _GFToggleState(); } @@ -86,15 +85,15 @@ class _GFToggleState extends State with TickerProviderStateMixin { bool isOn; - - @override void initState() { setState(() { - isOn = widget.value??false; + isOn = widget.value ?? false; }); controller = AnimationController(vsync: this, duration: widget.duration); - offset = (isOn?Tween(begin: Offset(1.0, 0.0), end:Offset.zero):Tween(begin: Offset.zero, end: Offset(1.0, 0.0))) + offset = (isOn + ? Tween(begin: Offset(1.0, 0.0), end: Offset.zero) + : Tween(begin: Offset.zero, end: Offset(1.0, 0.0))) .animate(controller); super.initState(); } @@ -106,8 +105,8 @@ class _GFToggleState extends State with TickerProviderStateMixin { super.dispose(); } - void onStatusChange(){ - if(widget.onChanged!=null){ + void onStatusChange() { + if (widget.onChanged != null) { setState(() { isOn = !isOn; }); @@ -127,84 +126,79 @@ class _GFToggleState extends State with TickerProviderStateMixin { @override Widget build(BuildContext context) { - return Stack( - children: [ - Container( - height: widget.type == GFToggleType.android ? 25 : 30, - width: widget.type == GFToggleType.android ? 40 : 50, - ), - Positioned( - top: 5, - child: InkWell( + return Stack( + children: [ + Container( + height: widget.type == GFToggleType.android ? 25 : 30, + width: widget.type == GFToggleType.android ? 40 : 50, + ), + Positioned( + top: 5, + child: InkWell( onTap: onStatusChange, child: Container( - width: widget.type == GFToggleType.ios ? 45 : 36, - height: widget.type == GFToggleType.ios ? 25 : 15, - decoration: BoxDecoration( - color: isOn - ? widget.enabledTrackColor ?? Colors.lightGreen - : widget.disabledTrackColor ?? Colors.grey, - borderRadius: widget.type == GFToggleType.square - ? BorderRadius.all(Radius.circular(0)) - : widget.borderRadius ?? + width: widget.type == GFToggleType.ios ? 45 : 36, + height: widget.type == GFToggleType.ios ? 25 : 15, + decoration: BoxDecoration( + color: isOn + ? widget.enabledTrackColor ?? Colors.lightGreen + : widget.disabledTrackColor ?? Colors.grey, + borderRadius: widget.type == GFToggleType.square + ? BorderRadius.all(Radius.circular(0)) + : widget.borderRadius ?? BorderRadius.all(Radius.circular(20))), - child: Padding( - padding: widget.type == GFToggleType.ios - ? EdgeInsets.only(left: 3.5, right: 3.5, top: 5.4) - : EdgeInsets.only(left: 3, right: 3, top: 3.4), - child: isOn - ? Text( - widget.enabledText ?? - (widget.type == GFToggleType.custom - ? 'ON' - : ''), - style: widget.enabledTextStyle ?? - (widget.type == GFToggleType.ios - ? TextStyle( - color: Colors.white, fontSize: 12) - : TextStyle( - color: Colors.white, fontSize: 8))) - : Text( - widget.disabledText ?? - (widget.type == GFToggleType.custom - ? 'OFF' - : ''), - textAlign: TextAlign.end, - style: widget.disabledTextStyle ?? - (widget.type == GFToggleType.ios - ? TextStyle(color: Colors.white, fontSize: 12) - : TextStyle(color: Colors.white, fontSize: 8)),),),), - ),), - Positioned( - top: widget.type == GFToggleType.ios ? 7.5 : 3, - left: widget.type == GFToggleType.ios ? 2 : 0, - child: InkWell( - onTap: onStatusChange, - child: SlideTransition( - position:offset, - child: Container( - padding: EdgeInsets.only(left: 10), - height: 20, - width: 20, - decoration: BoxDecoration( - shape: widget.type == GFToggleType.square - ? BoxShape.rectangle - : widget.boxShape ?? BoxShape.circle, - color: isOn - ? widget.enabledThumbColor ?? Colors.white - : widget.disabledThumbColor ?? Colors.white, - boxShadow: [ - new BoxShadow( - color: Colors.black.withOpacity(0.16), - blurRadius: 6.0, - spreadRadius: 0.0), - ]), + child: Padding( + padding: widget.type == GFToggleType.ios + ? EdgeInsets.only(left: 3.5, right: 3.5, top: 5.4) + : EdgeInsets.only(left: 3, right: 3, top: 3.4), + child: isOn + ? Text( + widget.enabledText ?? + (widget.type == GFToggleType.custom ? 'ON' : ''), + style: widget.enabledTextStyle ?? + (widget.type == GFToggleType.ios + ? TextStyle(color: Colors.white, fontSize: 12) + : TextStyle(color: Colors.white, fontSize: 8))) + : Text( + widget.disabledText ?? + (widget.type == GFToggleType.custom ? 'OFF' : ''), + textAlign: TextAlign.end, + style: widget.disabledTextStyle ?? + (widget.type == GFToggleType.ios + ? TextStyle(color: Colors.white, fontSize: 12) + : TextStyle(color: Colors.white, fontSize: 8)), ), - ) - )), - ], - - ); + ), + ), + ), + ), + Positioned( + top: widget.type == GFToggleType.ios ? 7.5 : 3, + left: widget.type == GFToggleType.ios ? 2 : 0, + child: InkWell( + onTap: onStatusChange, + child: SlideTransition( + position: offset, + child: Container( + padding: EdgeInsets.only(left: 10), + height: 20, + width: 20, + decoration: BoxDecoration( + shape: widget.type == GFToggleType.square + ? BoxShape.rectangle + : widget.boxShape ?? BoxShape.circle, + color: isOn + ? widget.enabledThumbColor ?? Colors.white + : widget.disabledThumbColor ?? Colors.white, + boxShadow: [ + new BoxShadow( + color: Colors.black.withOpacity(0.16), + blurRadius: 6.0, + spreadRadius: 0.0), + ]), + ), + ))), + ], + ); } } -