flutter_navigation_bar 0.1.2

  • Readme
  • Changelog
  • Example
  • Installing
  • 68

flutter_navigation_bar #

A Flutter plugin for drawing behind the Navigation Bar.

Getting Started #

This project is a starting point for a Flutter plug-in package, a specialized package that includes platform-specific implementation code for Android and/or iOS.

For help getting started with Flutter, view our online documentation, which offers tutorials, samples, guidance on mobile development, and a full API reference.

0.0.1 #

Call setNavigationBarTransparent() and this plugin will set activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN, WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN)

0.0.2 #

Added FLAG_LAYOUT_NO_LIMITS.

0.0.3 #

Minor change.

0.0.4 #

Flags are set on init.

0.0.5 #

Converted to Kotlin and Swift. Solved the problem with a transparent Navigation Bar (full screen) and still allowing for the use of safe areas that work with input. Added support for equal width sides in landscape.

0.0.6 #

Changed so that you can set any widget at any time and get the changes.

0.0.7 #

0.0.6 never got published!?

0.0.8 #

Only worked on the first page. Now works on all pages.

0.0.9 #

Multi page problem fix.

0.1.0 #

Min height for detection of Software Navigation Bar is 16.

0.1.1 #

Set SWIFT_VERSION to 4.1

0.1.2 #

Changed SWIFT_VERSION to 4.2

example/lib/main.dart

import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_navigation_bar/flutter_navigation_bar.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',

      theme: ThemeData(
        platform: TargetPlatform.iOS,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  ScrollController _scrollController;
  ScrollController _dateTimeController;

  bool dateTimeExpanded = false;

  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();

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

    FlutterNavigationBar(set_to_this: this);

    _scrollController = ScrollController();
    _dateTimeController = ScrollController();

    WidgetsBinding.instance.renderView.automaticSystemUiAdjustment = false;

  }

  @override
  dispose() {
    _scrollController.dispose();
    _dateTimeController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        Positioned.fill(
          top: 0,
          left: 0,
          child: Scaffold(
            extendBody: false,
            body: CupertinoPageScaffold(
              child: CustomScrollView(
                controller: _scrollController,
                slivers: <Widget>[
                  SliverPersistentHeader(
                    delegate: MySliverAppBar(expandedHeight: MediaQuery.of(context).size.height / 2 + MediaQuery.of(context).padding.top),
//              delegate: MySliverAppBar(expandedHeight: _screenHeight / 2),
                    pinned: true,
                  ),
                  SliverList(
                    delegate: SliverChildListDelegate([
                      SafeArea(
                        top: false,
                        child: Form(
                          key: _formKey,
                          child: SingleChildScrollView(
                            padding: const EdgeInsets.symmetric(horizontal: 16.0),
                            child: SafeArea(
                              top: false,
                              child: Column(
                                crossAxisAlignment: CrossAxisAlignment.stretch,
                                children: <Widget>[
                                  const SizedBox(height: 24.0),
                                  TextFormField(
                                    cursorColor: Colors.red,
                                    textCapitalization: TextCapitalization.words,
                                    decoration: const InputDecoration(
                                      border: UnderlineInputBorder(),
                                      filled: true,
                                      icon: Icon(Icons.person),
                                      hintText: 'What do people call you?',
                                      labelText: 'Name *',
                                    ),
                                  ),
                                  const SizedBox(height: 24.0),
                                  TextFormField(
                                    decoration: const InputDecoration(
                                      border: UnderlineInputBorder(),
                                      filled: true,
                                      icon: Icon(Icons.phone),
                                      hintText: 'Where can we reach you?',
                                      labelText: 'Phone Number *',
                                      prefixText: '+1',
                                    ),
                                    keyboardType: TextInputType.phone,
                                  ),
                                  const SizedBox(height: 24.0),
                                  TextFormField(
                                    decoration: const InputDecoration(
                                      border: UnderlineInputBorder(),
                                      filled: true,
                                      icon: Icon(Icons.email),
                                      hintText: 'Your email address',
                                      labelText: 'E-mail',
                                    ),
                                    keyboardType: TextInputType.emailAddress,
                                  ),
                                  const SizedBox(height: 24.0),
                                  TextFormField(
                                    decoration: const InputDecoration(
                                      border: OutlineInputBorder(),
                                      hintText: 'Tell us about yourself (e.g., write down what you do or what hobbies you have)',
                                      helperText: 'Keep it short, this is just a demo.',
                                      labelText: 'Life story',
                                    ),
                                    maxLines: 3,
                                  ),
                                  const SizedBox(height: 24.0),
                                  TextFormField(
                                    keyboardType: TextInputType.number,
                                    decoration: const InputDecoration(
                                      border: OutlineInputBorder(),
                                      labelText: 'Salary',
                                      prefixText: '\$',
                                      suffixText: 'USD',
                                      suffixStyle: TextStyle(color: Colors.green),
                                    ),
                                    maxLines: 1,
                                  ),
                                  const SizedBox(height: 24.0),
                                  TextFormField(
                                    decoration: const InputDecoration(
                                      border: UnderlineInputBorder(),
                                      filled: true,
                                      labelText: 'Re-type password',
                                    ),
                                    maxLength: 8,
                                    obscureText: true,
                                  ),
                                  const SizedBox(height: 24.0),
                                  Center(
                                    child: RaisedButton(
                                      child: const Text('Next page'),
                                      onPressed: () {
                                        Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) =>  SecondRoute()));
                                      },
                                    ),
                                  ),
                                  const SizedBox(height: 24.0),
                                  Text(FlutterNavigationBar().navigationBarHeight.toString(),
                                    style: Theme.of(context).textTheme.caption,
                                  ),
                                  const SizedBox(height: 24.0),
                                ],
                              ),
                            ),
                          ),
                        ),
                      ),
                    ]),
                  ),
                  SliverFillRemaining(
                    fillOverscroll: false,
                    hasScrollBody: true,
                  ),
                ],
              ),
            ),
          ),
        ),
        /// Paint the insets
        Positioned(
          bottom: 0,
          width: MediaQuery.of(context).size.width,
          height: FlutterNavigationBar().navigationBarHeight,
          child: IgnorePointer(
            child: Container(
              color: Colors.red.withAlpha(50),
            ),
          ),
        ),
        Positioned(
          top: 0,
          width: MediaQuery.of(context).size.width,
          height: FlutterNavigationBar().statusBarHeight,
          child: IgnorePointer(
            child: Container(
              color: Colors.lightGreenAccent.withAlpha(50),
            ),
          ),
        ),
        Positioned(
          top: FlutterNavigationBar().statusBarHeight,
          right: 0,
          width: FlutterNavigationBar().navigationBarWidthRight,
          height: MediaQuery.of(context).size.height-FlutterNavigationBar().navigationBarHeight-FlutterNavigationBar().statusBarHeight,
          child: IgnorePointer(
            child: Container(
              color: Colors.green.withAlpha(50),
            ),
          ),
        ),
        Positioned(
          top: FlutterNavigationBar().statusBarHeight,
          left: 0,
          width: FlutterNavigationBar().navigationBarWidthLeft,
          height: MediaQuery.of(context).size.height-FlutterNavigationBar().navigationBarHeight-FlutterNavigationBar().statusBarHeight,
          child: IgnorePointer(
            child: Container(
              color: Colors.blue.withAlpha(050),
            ),
          ),
        ),
      ],
    );
  }
}

/// Class to make a SliverAppBar that doesn't take up to much space
class MySliverAppBar extends SliverPersistentHeaderDelegate {
  final double expandedHeight;

  MySliverAppBar({@required this.expandedHeight});

  double getOpacity(BuildContext context, double shrinkOffset) {
    double _result = 1.0;
    if ((MediaQuery.of(context).padding.top) != 0) {
      _result = max(
        min(expandedHeight - shrinkOffset - (MediaQuery.of(context).padding.top) * 1.5, (MediaQuery.of(context).padding.top)) /
            (MediaQuery.of(context).padding.top),
        0,
      );
    } else {
      _result = max(
        min(expandedHeight - shrinkOffset - Theme.of(context).primaryTextTheme.title.fontSize, Theme.of(context).primaryTextTheme.title.fontSize) /
            Theme.of(context).primaryTextTheme.title.fontSize,
        0,
      );
    }
    return _result;
  }

  int getShadowOpacity(BuildContext context, double shrinkOffset) {
    double _result = 1.0;
    if ((MediaQuery.of(context).padding.top) != 0) {
      _result = max(
          min(expandedHeight - shrinkOffset - (MediaQuery.of(context).padding.top) / 3, (MediaQuery.of(context).padding.top)) /
              (MediaQuery.of(context).padding.top),
          0);
    } else {
      _result = 1.0;
    }
    return ((1 - _result) * 255).round();
  }

  @override
  Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
    return Stack(
      fit: StackFit.passthrough,
      children: [
        Container(
          height: ((expandedHeight - shrinkOffset + 0) > (MediaQuery.of(context).padding.top))
              ? (expandedHeight - shrinkOffset + 0)
              : (MediaQuery.of(context).padding.top),
          decoration: BoxDecoration(
            boxShadow: [
              BoxShadow(
                color: Colors.black.withAlpha(getShadowOpacity(context, shrinkOffset)),
                blurRadius: 8.0,
                spreadRadius: 20.0,
                offset: Offset(
                  0.0,
                  -20.0,
                ),
              ),
            ],
            gradient: LinearGradient(
              colors: <Color>[
                Theme.of(context).brightness == Brightness.light ? Color(0xFF005090) : Color(0xFF003070),
                Theme.of(context).brightness == Brightness.light ? Color(0xFF5070F0) : Color(0xFF3050D0),
              ],
              begin: Alignment.topCenter,
              end: Alignment.bottomCenter,
            ),
          ),
          child: Opacity(
            opacity: getOpacity(context, shrinkOffset),
            child: SafeArea(
              top: false,
              bottom: false,
              child: Container(
                alignment: Alignment.bottomCenter,
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: <Widget>[
                    FittedBox(
                      child: IconButton(
                        icon: Icon(
                          Icons.arrow_back_ios,
                          color: Theme.of(context).brightness == Brightness.light ? Colors.white : Colors.grey,
                        ),
                        onPressed: () {
                          ///Enable equal width to the two sides in landscape
                          ///Doesn't really work that well with the soft keyboard
                          FlutterNavigationBar().equalSides = true;
                        },
                      ),
                    ),
                    Text(
                      'Title',
                      style: TextStyle(
                        fontSize: Theme.of(context).primaryTextTheme.title.fontSize,
                        fontWeight: FontWeight.normal,
                        fontFamily: Theme.of(context).primaryTextTheme.title.fontFamily,
                        color: Theme.of(context).brightness == Brightness.light ? Colors.white : Colors.grey.shade300,
                        decoration: TextDecoration.none,
                      ),
                    ),
                    FittedBox(
                      child: IconButton(
                        icon: const Icon(
                          Icons.save_alt,
                          color: Colors.white,
                        ),
                        onPressed: () {
                          ///Disable equal width to the two sides in landscape
                          FlutterNavigationBar().equalSides = false;
                        },
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ),
        ),
      ],
    );
  }

  @override
  double get maxExtent => expandedHeight;

  @override
  double get minExtent => kToolbarHeight;

  @override
  bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true;
}

class SecondRoute extends StatefulWidget {

  @override
  _SecondRouteState createState() => _SecondRouteState();
}

class _SecondRouteState extends State<SecondRoute> {

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

    FlutterNavigationBar(set_to_this: this);
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        Positioned.fill(
          child: Scaffold(
            appBar: AppBar(
              title: Text("Second Route"),
            ),
            body: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Text(FlutterNavigationBar().navigationBarHeight.toString(),
                    style: Theme.of(context).textTheme.caption,
                  ),
                  RaisedButton(
                    onPressed: () {
                      Navigator.pop(context);
                    },
                    child: Text('Go back!'),
                  ),
                  TextField(

                  ),
                ],
              ),
            ),
          ),
        ),
        /// Paint the insets
        Positioned(
          bottom: 0,
          width: MediaQuery.of(context).size.width,
          height: FlutterNavigationBar().navigationBarHeight,
          child: IgnorePointer(
            child: Container(
              color: Colors.red.withAlpha(50),
            ),
          ),
        ),
        Positioned(
          top: 0,
          width: MediaQuery.of(context).size.width,
          height: FlutterNavigationBar().statusBarHeight,
          child: IgnorePointer(
            child: Container(
              color: Colors.lightGreenAccent.withAlpha(50),
            ),
          ),
        ),
        Positioned(
          top: FlutterNavigationBar().statusBarHeight,
          right: 0,
          width: FlutterNavigationBar().navigationBarWidthRight,
          height: MediaQuery.of(context).size.height-FlutterNavigationBar().navigationBarHeight-FlutterNavigationBar().statusBarHeight,
          child: IgnorePointer(
            child: Container(
              color: Colors.green.withAlpha(50),
            ),
          ),
        ),
        Positioned(
          top: FlutterNavigationBar().statusBarHeight,
          left: 0,
          width: FlutterNavigationBar().navigationBarWidthLeft,
          height: MediaQuery.of(context).size.height-FlutterNavigationBar().navigationBarHeight-FlutterNavigationBar().statusBarHeight,
          child: IgnorePointer(
            child: Container(
              color: Colors.blue.withAlpha(050),
            ),
          ),
        ),
      ],
    );
  }
}

Use this package as a library

1. Depend on it

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


dependencies:
  flutter_navigation_bar: ^0.1.2

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

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

3. Import it

Now in your Dart code, you can use:


import 'package:flutter_navigation_bar/flutter_navigation_bar.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
39
Health:
Code health derived from static analysis. [more]
99
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
95
Overall:
Weighted score of the above. [more]
68
Learn more about scoring.

We analyzed this package on Mar 31, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.7.1
  • pana: 0.13.6
  • Flutter: 1.12.13+hotfix.8

Health suggestions

Fix lib/flutter_navigation_bar.dart. (-1.49 points)

Analysis of lib/flutter_navigation_bar.dart reported 3 hints:

line 86 col 16: Don't explicitly initialize variables to null.

line 153 col 55: Name non-constant identifiers using lowerCamelCase.

line 167 col 37: The member 'setState' can only be used within instance members of subclasses of 'package:flutter/src/widgets/framework.dart'.

Maintenance suggestions

The package description is too short. (-5 points)

Add more detail to the description field of pubspec.yaml. Use 60 to 180 characters to describe the package, what it does, and its target use case.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.1.0 <3.0.0
flutter 0.0.0
Transitive dependencies
collection 1.14.11 1.14.12
meta 1.1.8
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test