Coder Social home page Coder Social logo

rodydavis / floating_search_bar Goto Github PK

View Code? Open in Web Editor NEW
32.0 2.0 27.0 1.21 MB

Floating Search Bar like Gmail for Flutter

Home Page: https://rodydavis.github.io/floating_search_bar/

License: MIT License

Kotlin 1.95% Shell 2.72% Swift 5.50% Objective-C 0.18% Dart 84.74% HTML 4.91%

floating_search_bar's Introduction

Buy Me A Coffee Donate

floating_search_bar

A Search App Bar like the one in Gmail and Google Photos.

Online Demo: https://rodydavis.github.io/floating_search_bar/

Getting Started

If you want to just use the floating bar as an app bar please use SliverFloatingBar otherwise use FloatingSearchBar.

search

if you add a drawer the menu icon will show up:

drawer

Usage

import 'package:flutter/material.dart';

import 'package:floating_search_bar/floating_search_bar.dart';

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: FloatingSearchBar.builder(
        itemCount: 100,
        itemBuilder: (BuildContext context, int index) {
          return ListTile(
            leading: Text(index.toString()),
          );
        },
        trailing: CircleAvatar(
          child: Text("RD"),
        ),
        drawer: Drawer(
          child: Container(),
        ),
        onChanged: (String value) {},
        onTap: () {},
        decoration: InputDecoration.collapsed(
          hintText: "Search...",
        ),
      ),
    );
  }
}

floating_search_bar's People

Contributors

rodydavis avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

floating_search_bar's Issues

After updating flutter, it's causing dependency problems

So with latest stable channel of flutter it is giving following error on pub get command!
/C:/src/flutter/flutter/.pub-cache/hosted/pub.dartlang.org/floating_search_bar-0.3.0/lib/ui/sliver_search_bar.dart:242:20: Error: The method 'ancestorRenderObjectOfType' isn't defined for the class 'BuildContext'.

I solved this by using flutter dev channel. But it is not working in stable channel!
My configuration :

Flutter 2.0.4 • channel stable • https://github.com/flutter/flutter.git
Framework • revision b1395592de (4 days ago) • 2021-04-01 14:25:01 -0700
Engine • revision 2dce47073a
Tools • Dart 2.12.2

[floating_search_bar] focus on tap

The actual TextField of the search bar is just as high as the textSize. At least for me that is way too small to accurately hit it with a tap to get focus and open the keyboard. The TextField should get focus no matter where the user taps inside the search bar.

[feature request] FloatingSearchBar - TextInputAction Search

The text input action for the FloatingSearchBar should be set to search or be configurable. See updated code below.

File: floating_search_bar.dart

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      drawer: drawer,
      endDrawer: endDrawer,
      body: CustomScrollView(
        slivers: <Widget>[
          SliverFloatingBar(
            leading: leading,
            floating: true,
            title: title ??
                TextField(
                  textInputAction: TextInputAction.search,    <---------------- Line added
                  controller: controller,
                  decoration: decoration ??
                      InputDecoration.collapsed(
                        hintText: "Search...",
                      ),
                  autofocus: false,
                  onChanged: onChanged,
                  onTap: onTap,
                ),
            trailing: trailing,
          ),
          SliverList(
            delegate: _childDelagate,
          ),
        ],
      ),
    );
  }

[feature request] FloatingSearchBar - Top Padding

The padding at the top of FloatingSearchBar should be configurable so that a small region can be inserted between the search bar and the top of the containder. I suggest a non-zero default of 12, consistent with the left/right padding.

File: sliver_search_bar.dart
Location _SliverAppBarDelegate.build (line 347)

    final Widget appBar = FlexibleSpaceBar.createSettings(
      minExtent: minExtent,
      maxExtent: maxExtent,
      currentExtent: math.max(minExtent, maxExtent - shrinkOffset), 
      toolbarOpacity: toolbarOpacity,
      child: Container(
        padding: this.padding,       <---------------------------------------- Line updated, supplied by user
        child: SafeArea(
          child: Material(
            color: backgroundColor,
            borderRadius: BorderRadius.circular(8.0),

Screenshot_1562456466

Null Safety

Hi,

are you planning to migrate this library to sound null safety?
If you don't have time yourself, would you accept pull requests in this direction and make a Prerelease?

Error: The method 'ancestorRenderObjectOfType' isn't defined for the class

Hi i have just updated flutter version to 2.0 .

I am getting error as below.

/C:/src/flutter/.pub-cache/hosted/pub.dartlang.org/floating_search_bar-0.3.0/lib/ui/sliver_search_bar.dart:242:20: Error: The method 'ancestorRenderObjectOfType' isn't defined for the class 'BuildContext'.

  • 'BuildContext' is from 'package:flutter/src/widgets/framework.dart' ('/C:/src/flutter/packages/flutter/lib/src/widgets/framework.dart').
    Try correcting the name to the name of an existing method, or defining a method named 'ancestorRenderObjectOfType'.
    return context.ancestorRenderObjectOfType(
    ^^^^^^^^^^^^^^^^^^^^^^^^^^

Can anyone give me solution for this

Android update margin top: : Matrix4.translationValues(0.0, 8.0, 0.0)

import 'dart:math' as math;

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/foundation.dart' show TargetPlatform;

class SliverFloatingBar extends StatefulWidget {
/// Creates a material design app bar that can be placed in a [CustomScrollView].
///
/// The arguments [forceElevated], [primary], [floating], [pinned], [snap]
/// and [automaticallyImplyLeading] must not be null.
const SliverFloatingBar({
Key key,
this.leading,
this.automaticallyImplyLeading = true,
this.title,
this.trailing,
this.elevation = 5.0,
this.backgroundColor,
this.floating = false,
this.pinned = false,
this.snap = false,
}) : assert(automaticallyImplyLeading != null),
assert(floating != null),
assert(pinned != null),
assert(snap != null),
assert(floating || !snap,
'The "snap" argument only makes sense for floating app bars.'),
super(key: key);

/// A widget to display before the [title].
///
/// If this is null and [automaticallyImplyLeading] is set to true, the [AppBar] will
/// imply an appropriate widget. For example, if the [AppBar] is in a [Scaffold]
/// that also has a [Drawer], the [Scaffold] will fill this widget with an
/// [IconButton] that opens the drawer. If there's no [Drawer] and the parent
/// [Navigator] can go back, the [AppBar] will use a [BackButton] that calls
/// [Navigator.maybePop].
final Widget leading;

/// Controls whether we should try to imply the leading widget if null.
///
/// If true and [leading] is null, automatically try to deduce what the leading
/// widget should be. If false and [leading] is null, leading space is given to [title].
/// If leading widget is not null, this parameter has no effect.
final bool automaticallyImplyLeading;

/// The primary widget displayed in the appbar.
///
/// Typically a [Text] widget containing a description of the current contents
/// of the app.
final Widget title;

final Widget trailing;

/// The z-coordinate at which to place this app bar when it is above other
/// content. This controls the size of the shadow below the app bar.
///
/// Defaults to 4, the appropriate elevation for app bars.
///
/// If [forceElevated] is false, the elevation is ignored when the app bar has
/// no content underneath it. For example, if the app bar is [pinned] but no
/// content is scrolled under it, or if it scrolls with the content, then no
/// shadow is drawn, regardless of the value of [elevation].
final double elevation;

/// The color to use for the app bar's material. Typically this should be set
/// along with [brightness], [iconTheme], [textTheme].
///
/// Defaults to [ThemeData.primaryColor].
final Color backgroundColor;

/// Whether the app bar should become visible as soon as the user scrolls
/// towards the app bar.
///
/// Otherwise, the user will need to scroll near the top of the scroll view to
/// reveal the app bar.
///
/// If [snap] is true then a scroll that exposes the app bar will trigger an
/// animation that slides the entire app bar into view. Similarly if a scroll
/// dismisses the app bar, the animation will slide it completely out of view.
///
/// ## Animated Examples
///
/// The following animations show how the app bar changes its scrolling
/// behavior based on the value of this property.
///
/// * App bar with [floating] set to false:
/// {@animation 476 400 https://flutter.github.io/assets-for-api-docs/assets/material/app_bar.mp4}
/// * App bar with [floating] set to true:
/// {@animation 476 400 https://flutter.github.io/assets-for-api-docs/assets/material/app_bar_floating.mp4}
///
/// See also:
///
/// * [SliverAppBar] for more animated examples of how this property changes the
/// behavior of the app bar in combination with [pinned] and [snap].
final bool floating;

/// Whether the app bar should remain visible at the start of the scroll view.
///
/// The app bar can still expand and contract as the user scrolls, but it will
/// remain visible rather than being scrolled out of view.
///
/// ## Animated Examples
///
/// The following animations show how the app bar changes its scrolling
/// behavior based on the value of this property.
///
/// * App bar with [pinned] set to false:
/// {@animation 476 400 https://flutter.github.io/assets-for-api-docs/assets/material/app_bar.mp4}
/// * App bar with [pinned] set to true:
/// {@animation 476 400 https://flutter.github.io/assets-for-api-docs/assets/material/app_bar_pinned.mp4}
///
/// See also:
///
/// * [SliverAppBar] for more animated examples of how this property changes the
/// behavior of the app bar in combination with [floating].
final bool pinned;

/// If [snap] and [floating] are true then the floating app bar will "snap"
/// into view.
///
/// If [snap] is true then a scroll that exposes the floating app bar will
/// trigger an animation that slides the entire app bar into view. Similarly if
/// a scroll dismisses the app bar, the animation will slide the app bar
/// completely out of view.
///
/// Snapping only applies when the app bar is floating, not when the appbar
/// appears at the top of its scroll view.
///
/// ## Animated Examples
///
/// The following animations show how the app bar changes its scrolling
/// behavior based on the value of this property.
///
/// * App bar with [snap] set to false:
/// {@animation 476 400 https://flutter.github.io/assets-for-api-docs/assets/material/app_bar_floating.mp4}
/// * App bar with [snap] set to true:
/// {@animation 476 400 https://flutter.github.io/assets-for-api-docs/assets/material/app_bar_floating_snap.mp4}
///
/// See also:
///
/// * [SliverAppBar] for more animated examples of how this property changes the
/// behavior of the app bar in combination with [pinned] and [floating].
final bool snap;

@OverRide
_SliverFloatingBarState createState() => _SliverFloatingBarState();
}

class _SliverFloatingBarState extends State
with TickerProviderStateMixin {
FloatingHeaderSnapConfiguration _snapConfiguration;

void _updateSnapConfiguration() {
if (widget.snap && widget.floating) {
_snapConfiguration = FloatingHeaderSnapConfiguration(
vsync: this,
curve: Curves.easeOut,
duration: const Duration(milliseconds: 200),
);
} else {
_snapConfiguration = null;
}
}

@OverRide
void initState() {
super.initState();

_updateSnapConfiguration();

}

@OverRide
void didUpdateWidget(SliverFloatingBar oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.snap != oldWidget.snap || widget.floating != oldWidget.floating)
_updateSnapConfiguration();
}

@OverRide
Widget build(BuildContext context) {
final double topPadding = MediaQuery.of(context).padding.top;
final double collapsedHeight =
(widget.pinned && widget.floating) ? topPadding : null;

return MediaQuery.removePadding(
  context: context,
  removeBottom: true,
  child: SliverPersistentHeader(
    floating: widget.floating,
    pinned: widget.pinned,
    delegate: _SliverAppBarDelegate(
      leading: widget.leading,
      automaticallyImplyLeading: widget.automaticallyImplyLeading,
      title: widget.title,
      trailing: widget.trailing,
      elevation: widget.elevation,
      backgroundColor: widget.backgroundColor,
      floating: widget.floating,
      pinned: widget.pinned,
      snapConfiguration: _snapConfiguration,
      collapsedHeight: collapsedHeight,
      topPadding: topPadding,
    ),
  ),
);

}
}

class _FloatingAppBar extends StatefulWidget {
const _FloatingAppBar({Key key, this.child}) : super(key: key);

final Widget child;

@OverRide
_FloatingAppBarState createState() => _FloatingAppBarState();
}

// A wrapper for the widget created by _SliverAppBarDelegate that starts and
/// stops the floating appbar's snap-into-view or snap-out-of-view animation.
class _FloatingAppBarState extends State<_FloatingAppBar> {
ScrollPosition _position;

@OverRide
void didChangeDependencies() {
super.didChangeDependencies();
if (_position != null)
_position.isScrollingNotifier.removeListener(_isScrollingListener);
_position = Scrollable.of(context)?.position;
if (_position != null)
_position.isScrollingNotifier.addListener(_isScrollingListener);
}

@OverRide
void dispose() {
if (_position != null)
_position.isScrollingNotifier.removeListener(_isScrollingListener);
super.dispose();
}

RenderSliverFloatingPersistentHeader _headerRenderer() {
return context.ancestorRenderObjectOfType(
const TypeMatcher());
}

void _isScrollingListener() {
if (_position == null) return;

// When a scroll stops, then maybe snap the appbar into view.
// Similarly, when a scroll starts, then maybe stop the snap animation.
final RenderSliverFloatingPersistentHeader header = _headerRenderer();
if (_position.isScrollingNotifier.value)
  header?.maybeStopSnapAnimation(_position.userScrollDirection);
else
  header?.maybeStartSnapAnimation(_position.userScrollDirection);

}

@OverRide
Widget build(BuildContext context) => widget.child;
}

class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
_SliverAppBarDelegate({
@required this.leading,
@required this.automaticallyImplyLeading,
@required this.title,
@required this.trailing,
@required this.elevation,
@required this.backgroundColor,
@required this.floating,
@required this.pinned,
@required this.snapConfiguration,
@required this.collapsedHeight,
@required this.topPadding,
});

final Widget trailing;
final bool automaticallyImplyLeading;
final Color backgroundColor;
final double elevation;
final bool floating;
final Widget leading;
final bool pinned;
final Widget title;
final double collapsedHeight;
final double topPadding;

@OverRide
double get minExtent => collapsedHeight ?? (topPadding + kToolbarHeight);

@OverRide
final FloatingHeaderSnapConfiguration snapConfiguration;

@OverRide
double get maxExtent => math.max(topPadding + (kToolbarHeight), minExtent);

@OverRide
bool shouldRebuild(covariant _SliverAppBarDelegate oldDelegate) {
return leading != oldDelegate.leading ||
automaticallyImplyLeading != oldDelegate.automaticallyImplyLeading ||
title != oldDelegate.title ||
trailing != oldDelegate.trailing ||
elevation != oldDelegate.elevation ||
topPadding != oldDelegate.topPadding ||
collapsedHeight != oldDelegate.collapsedHeight ||
backgroundColor != oldDelegate.backgroundColor ||
pinned != oldDelegate.pinned ||
floating != oldDelegate.floating ||
snapConfiguration != oldDelegate.snapConfiguration;
}

@OverRide
String toString() {
return '';
}

@OverRide
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
final double visibleMainHeight = maxExtent - shrinkOffset;
var platform = Theme.of(context).platform;
// // Truth table for toolbarOpacity:
// // pinned | floating | bottom != null || opacity
// // ----------------------------------------------
// // 0 | 0 | 0 || fade
// // 0 | 0 | 1 || fade
// // 0 | 1 | 0 || fade
// // 0 | 1 | 1 || fade
// // 1 | 0 | 0 || 1.0
// // 1 | 0 | 1 || 1.0
// // 1 | 1 | 0 || 1.0
// // 1 | 1 | 1 || fade
final double toolbarOpacity = !pinned || (floating)
? ((visibleMainHeight) / kToolbarHeight).clamp(0.0, 1.0)
: 1.0;

final Widget appBar = FlexibleSpaceBar.createSettings(
  minExtent: minExtent,
  maxExtent: maxExtent,
  currentExtent: math.max(minExtent, maxExtent - shrinkOffset),
  toolbarOpacity: toolbarOpacity,
  child: Container(
    //  margin: const EdgeInsets.only(top: 10.0),
    padding: EdgeInsets.symmetric(horizontal: 12.0),
    child: SafeArea(
      child: Material(
        color: backgroundColor,
        borderRadius: BorderRadius.circular(8.0),
        elevation: elevation,
        child: ListTile(
          leading: leading ??
              (Scaffold.of(context).hasDrawer && automaticallyImplyLeading
                  ? IconButton(
                      icon: Icon(Icons.menu),
                      onPressed: () {
                        Scaffold.of(context).openDrawer();
                      },
                    )
                  : null),
          title: title,
          trailing: trailing ??
              (Scaffold.of(context).hasEndDrawer &&
                      automaticallyImplyLeading
                  ? IconButton(
                      icon: Icon(Icons.menu),
                      onPressed: () {
                        Scaffold.of(context).openEndDrawer();
                      },
                    )
                  : null),
        ),
      ),
    ),
    transform: platform == TargetPlatform.iOS
        ? Matrix4.translationValues(0.0, 0.0, 0.0)
        : Matrix4.translationValues(0.0, 8.0, 0.0),
  ),
);
return Container(child: floating ? _FloatingAppBar(child: appBar) : appBar);

}
}

Provide empty state builder

When the list is empty it should be possible to show a widget with a message to the user to change the search criteria.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.