Giter Club home page Giter Club logo

flutter-floating-bottom-bar's Introduction

Floating Bottom Bar

A flutter package which allows to show a floating widget which can be used as a tab bar, bottom navigation bar or anything one can think of. The widget reacts to scrolling events too.


Platform Pub Package License: MIT Donate


A floating tab bar A floating search bar A basic example
A floating tab bar A floating search bar A basic example
image
A floating tab bar with a FAB

Features

The package allows you to create a floating widget like a bottom navigation bar that reacts to scrolling events.

  • It can be used as a tab bar, bottom navigation bar or anything one can think of.
  • It reacts to scrolling events too.
  • It can be used in a full screen app or in a smaller screen.

Installing

1. Depend on it

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

dependencies:
  flutter_floating_bottom_bar: ^1.2.0

2. Install it

You can install packages from the command line:

with pub:

pub get

with Flutter:

flutter pub get

3. Import it

Now in your Dart code, you can use:

import 'package:flutter_floating_bottom_bar/flutter_floating_bottom_bar.dart';

Usage

BottomBar is a Widget that can be wrapped over any child to convert it into a bottom bar. Below is the most simple use:

    BottomBar(
          child: Padding(
            padding: const EdgeInsets.all(16.0),
            child: Text(
              "This is the floating widget",
              textAlign: TextAlign.center,
              style: TextStyle(color: Colors.white),
            ),
          ),
          body: (context, controller) =>
              InfiniteListPage(controller: controller, color: Colors.blue,),
    )

It needs two required arguments -

  • child – This is the child inside the BottomBar (widget which is floating)
  • body – The widget displayed below the BottomBar (like your main app)

Detailed Usage

Below is the detailed usage of the package, including all properties defined.

BottomBar(
          child: TabBar(), # A floating tab bar
          fit: StackFit.expand,
          icon: (width, height) => Center(
            child: IconButton(
              padding: EdgeInsets.zero,
              onPressed: null,
              icon: Icon(
                Icons.arrow_upward_rounded,
                color: unselectedColor,
                size: width,
              ),
            ),
          ),
          borderRadius: BorderRadius.circular(500),
          duration: Duration(seconds: 1),
          curve: Curves.decelerate,
          showIcon: true,
          width: MediaQuery.of(context).size.width * 0.8,
          barColor: colors[currentPage].computeLuminance() > 0.5 ? Colors.black : Colors.white,
          start: 2,
          end: 0,
          offset: 10,
          barAlignment: Alignment.bottomCenter,
          iconHeight: 35,
          iconWidth: 35,
          reverse: false,
          barDecoration: BoxDecoration(
            color: colors[currentPage],
            borderRadius: BorderRadius.circular(500),
          ),
          iconDecoration: BoxDecoration(
            color: colors[currentPage],
            borderRadius: BorderRadius.circular(500),
          ),
          hideOnScroll: true,
          scrollOpposite: false,
          onBottomBarHidden: () {},
          onBottomBarShown: () {},
          body: (context, controller) => TabBarView(
            controller: tabController,
            dragStartBehavior: DragStartBehavior.down,
            physics: const BouncingScrollPhysics(),
            children: [] # Add children here
          ),
        )

icon

    icon: Center(
            child: IconButton(
              padding: EdgeInsets.zero,
              onPressed: null,
              icon: Icon(
                Icons.arrow_upward_rounded,
                color: unselectedColor,
              ),
            ),
          ),

This is the scroll to top button. It will be hidden when the BottomBar is scrolled up. It will be shown when the BottomBar is scrolled down. Clicking it will scroll the bar on top.

You can hide this by using the showIcon property.

iconWidth

    iconWidth: 35,

The width of the scroll to top button.

iconHeight

    iconHeight: 35,

The height of the scroll to top button.

barColor

     barColor: Colors.white,

The color of the BottomBar.

end

     end: 0,

The end position in y-axis of the SlideTransition of the BottomBar.

start

     start: 2,

The start position in y-axis of the SlideTransition of the BottomBar.

offset

     offset: 10,

The padding/offset from all sides of the bar in double.

duration

     duration: Duration(seconds: 1),

The duration of the SlideTransition of the BottomBar.

curve

     curve: Curves.decelerate,

The curve of the SlideTransition of the BottomBar.

width

     width: MediaQuery.of(context).size.width * 0.8,

The width of the BottomBar.

borderRadius

     borderRadius: BorderRadius.circular(500),

The border radius of the BottomBar.

showIcon

     showIcon: true,

If you don't want the scroll to top button to be visible, set this to false.

alignment (deprecated)

     alignment: Alignment.bottomCenter,

The alignment of the Stack in which the BottomBar is placed.

Note - This property is deprecated. Use barAlignment instead.

barAlignment

     barAlignment: Alignment.bottomCenter,

The alignment of the Bar and the icon in the Stack in which the BottomBar is placed.

onBottomBarShown

     onBottomBarShown: () {},

The callback when the BottomBar is shown i.e. on response to scroll events.

onBottomBarHidden

     onBottomBarHidden: () {},

The callback when the BottomBar is hidden i.e. on response to scroll events.

reverse

     reverse: true,

To reverse the direction in which the scroll reacts, i.e. if you want to make the bar visible when you scroll down and hide it when you scroll up, set this to true.

scrollOpposite

     scrollOpposite: true,

To reverse the direction in which the scroll to top button scrolls, i.e. if you want to scroll to bottom, set this to true.

hideOnScroll

     hideOnScroll: false,

If you don't want the bar to be hidden ever, set this to false.

fit

     fit: StackFit.expand,

The fit property of the Stack in which the BottomBar is placed.

clip

     clip: Clip.none,

The clipBehaviour property of the Stack in which the BottomBar is placed.

barDecoration

     barDecoration: BoxDecoration(
            color: Colors.red,
            borderRadius: BorderRadius.circular(500),
          ),

The BoxDecoration for the BottomBar.

iconDecoration

     iconDecoration: BoxDecoration(
            color: Colors.white,
            borderRadius: BorderRadius.circular(500),
          ),

The BoxDecoration for the scroll to top icon shown when BottomBar is hidden.

Note - You can find more detailed examples in the example directory.

Bugs or Requests

If you encounter any problems feel free to open an issue. If you feel the library is missing a feature, please raise a ticket on GitHub and I'll look into it. Pull request are also welcome.

See Contributing.md.

flutter-floating-bottom-bar's People

Contributors

chintan100 avatar codenameakshay avatar janzeman 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

Watchers

 avatar  avatar

flutter-floating-bottom-bar's Issues

Exception in your example app: The provided ScrollController is currently attached to more than one ScrollPosition.

Repro steps:

  1. Run your sample app via flutter run -d windows
  2. Scroll down to let's say line 500 on the first yellow tab
  3. Scroll up and QUICKLY switch to the second red tab
  4. Keep trying there and back - usually I get it reproduce within 30 seconds.

`══╡ EXCEPTION CAUGHT BY ANIMATION LIBRARY ╞═════════════════════════════════════════════════════════
The following assertion was thrown while notifying status listeners for AnimationController:
The provided ScrollController is currently attached to more than one ScrollPosition.
The Scrollbar requires a single ScrollPosition in order to be painted.
When the scrollbar is interactive, the associated ScrollController must only have one ScrollPosition
attached.The provided ScrollController must be unique to one ScrollView widget.

When the exception was thrown, this was the stack:
0 RawScrollbarState._debugCheckHasValidScrollPosition. (package:flutter/src/widgets/scrollbar.dart:1492:9)
1 RawScrollbarState._debugCheckHasValidScrollPosition (package:flutter/src/widgets/scrollbar.dart:1517:6)
2 RawScrollbarState._validateInteractions (package:flutter/src/widgets/scrollbar.dart:1428:14)
3 AnimationLocalStatusListenersMixin.notifyStatusListeners (package:flutter/src/animation/listener_helpers.dart:240:19)
4 AnimationController._checkStatusChanged (package:flutter/src/animation/animation_controller.dart:815:7)
5 AnimationController._startSimulation (package:flutter/src/animation/animation_controller.dart:749:5)
6 AnimationController._animateToInternal (package:flutter/src/animation/animation_controller.dart:612:12)
7 AnimationController.reverse (package:flutter/src/animation/animation_controller.dart:495:12)
8 RawScrollbarState._maybeStartFadeoutTimer. (package:flutter/src/widgets/scrollbar.dart:1625:37)
12 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
(elided 3 frames from class _Timer and dart:async-patch)

The AnimationController notifying status listeners was:
AnimationController#f54e4(◀ 1.000)
════════════════════════════════════════════════════════════════════════════════════════════════════`

Error when attaching multiple scroll controller

I'm getting error when attaching scroll controller on multiple widget page. This happened when I'm scrolling one page then swipe TabBarView to move into another page.

My code attaching scroll controller
Tangkapan Layar 2023-11-02 pukul 09 38 15

Line error from VS Code Debug
Tangkapan Layar 2023-11-02 pukul 09 40 10

Overlaying a button on the BottomBar without it clipping

Hi there - would it be possible to add support for the below please?

I'm trying to create a floating button over the bar, but it appears to be clipping the content and Clip.none is not resolving it.

This is what I'm trying to achieve (Figma design):
image

But at the moment it's clipping the button like below. The clipBehavior: Clip.none, attribute doesn't seem to be taking effect.
image

Please advise on how best to tackle this? Added code below.

body: Stack(
              alignment: Alignment.bottomCenter,
              clipBehavior:
                  Clip.none, //! this doesn't seem to be doing anything
              children: [
                BottomBar(
                  child: Stack(
                    alignment: Alignment.topCenter,
                    clipBehavior: Clip.none,
                    children: [
                      TabBar(
                        indicatorPadding:
                            const EdgeInsets.fromLTRB(6.0, 0.0, 6.0, 0.0),
                        controller: tabController,
                        indicator: UnderlineTabIndicator(
                          borderSide: BorderSide(
                            color: Colors.orange,
                            width: 4,
                          ),
                          insets: EdgeInsets.fromLTRB(20.0, 0.0, 20.0, 8.0),
                        ),
                        tabs: [
                          SizedBox(
                            height: 62,
                            child: Center(
                              child: Container(
                                padding:
                                    EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0),
                                child: Column(
                                  children: [
                                    Icon(
                                      Icons.explore,
                                      color: currentPage == 0
                                          ? Colors.indigo[900]
                                          : unselectedColor,
                                    ),
                                    Text(
                                      'Discover',
                                      style: TextStyle(
                                        fontSize: 12.0,
                                        color: currentPage == 0
                                            ? Colors.indigo[900]
                                            : unselectedColor,
                                        fontWeight: FontWeight.bold,
                                      ),
                                    ),
                                  ],
                                ),
                              ),
                            ),
                          ),
                          SizedBox(
                            height: 62,
                            child: Center(
                              child: Container(
                                padding:
                                    EdgeInsets.fromLTRB(0.0, 5.0, 0.0, 10.0),
                                child: Column(
                                  children: [
                                    Icon(
                                      Icons.person,
                                      color: currentPage == 1
                                          ? Colors.indigo[900]
                                          : unselectedColor,
                                    ),
                                    Text(
                                      'Profile',
                                      style: TextStyle(
                                        fontSize: 12.0,
                                        color: currentPage == 1
                                            ? Colors.indigo[900]
                                            : unselectedColor,
                                        fontWeight: FontWeight.bold,
                                      ),
                                    ),
                                  ],
                                ),
                              ),
                            ),
                          ),
                        ],
                      ),
                      Positioned(
                        top: -20,
                        child: Container(
                          alignment: Alignment.topCenter,
                          child: ElevatedButton(
                            onPressed: () {},
                            child: Icon(
                              Icons.add,
                              color: Colors.white,
                              size: 35.0,
                            ),
                            style: ElevatedButton.styleFrom(
                              shape: CircleBorder(),
                              padding: EdgeInsets.all(10.0),
                              primary: Colors.orange,
                              elevation: 1.0,
                            ),
                          ),
                        ),
                      ),
                    ],
                  ),
                  fit: StackFit.expand,
                  icon: Center(
                    child: IconButton(
                        padding: EdgeInsets.zero,
                        onPressed: null,
                        icon: Icon(
                          Icons.arrow_upward_rounded,
                          color: unselectedColor,
                        )),
                  ),
                  borderRadius: BorderRadius.circular(500),
                  duration: Duration(seconds: 1),
                  curve: Curves.decelerate,
                  showIcon: true,
                  width: MediaQuery.of(context).size.width * 0.8,
                  barColor: Colors.white,
                  start: 1,
                  end: 0,
                  bottom: 15, //This seems a bit dodgy... Keep an eye
                  alignment: Alignment.bottomCenter,
                  iconHeight: 45.0,
                  iconWidth: 45.0,
                  reverse: false,
                  scrollOpposite: false,
                  onBottomBarHidden: () {},
                  onBottomBarShown: () {},
                  body: (context, controller) => TabBarView(
                    controller: tabController,
                    dragStartBehavior: DragStartBehavior.down,
                    physics: const BouncingScrollPhysics(),
                    children: [
                      // ! The number of children here must equal the number of tabs specified above
                      Discover(),
                      Profile(),
                    ],
                  ),
                ),
                // Container(
                //   margin: EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 45.0),
                //   child: ElevatedButton(
                //     onPressed: () {},
                //     child: Icon(
                //       Icons.add,
                //       color: Colors.white,
                //       size: 35.0,
                //     ),
                //     style: ElevatedButton.styleFrom(
                //       shape: CircleBorder(),
                //       padding: EdgeInsets.all(10.0),
                //       primary: Colors.orange,
                //       elevation: 1.0,
                //     ),
                //   ),
                // ),
              ],
            ),

Unexpected white line on the Sample app TabBar

Please see the attached image. There is a thin white line there that disturbs users. The same line is not present on your demo gifs: https://raw.githubusercontent.com/codenameakshay/flutter-floating-bottom-bar/main/screenshots/1.gif

I am a Flutter beginner but will investigate further. It seems to be some kind of 'baseline' for the TabIndicator. I can easily modify the indicator itself by changing indicator or UnderlineTabIndicator properties but I cannot get rid of that white horizontal (base)line.

Or is it because your environment hasn't been updated for a while? I mean: sdk: ">=2.12.0 <3.0.0" whereas my newly created project shows sdk: '>=3.2.3 <4.0.0'.

image

A couple of errors to flag

Getting a couple of errors - apologies if this is just something I've missed:

  1. [No MediaQuery widget ancestor found] linked to the line "width: MediaQuery.of(context).size.width - 32,"... Do we need to wrap in Material App or something like that?

  2. The method 'InfiniteListPage' isn't defined for the type 'MyHomePage'

click animation overflow

animation over flow the rounded bar on click

image

suggestion

it would be more customizable if the box decoration became a property instead of only the color

Unpleasant overlay effect

The default overlay effect within the TabBar does not look nice. The fact it is rendered out of the curved border makes it unpleasant to look at IMHO.

Similar to previously reported bug the fix seems to be a one-liner, the PR will follow...

image
image

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.