stretchy_header 1.0.8

  • Readme
  • Changelog
  • Example
  • Installing
  • 90

Stretchy Header #

pub package

This package allows us to create a elastic header, to give a good effect when you scroll down the widget.

Sample 1

Sample 2

Sample 3


https://media.giphy.com/media/1NUOenNf2oKU3YuWb1/giphy.gif

Getting started #

You should ensure that you add the router as a dependency in your flutter project.

dependencies:
  stretchy_header: "^1.0.8"

You should then run flutter packages upgrade or update your packages in IntelliJ.

Example Project #

There is an example project in the example folder. Check it out. Otherwise, keep reading to get up and running.

Usage #

Sample 1 #

import 'package:flutter/material.dart';
import 'package:stretchy_header/stretchy_header.dart';

class SampleListView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: StretchyHeader.listViewBuilder(
        headerData: HeaderData(
          headerHeight: 250,
          header: Image.asset(
            "images/chichen.jpg",
            fit: BoxFit.cover,
          ),
        ),
        itemCount: 15,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text("item $index"),
            onTap: () {
              final snackBar = SnackBar(
                content: Text('item $index tapped'),
              );
              Scaffold.of(context).showSnackBar(snackBar);
            },
          );
        },
      ),
    );
  }
}

Sample 2 #

import 'package:flutter/material.dart';
import 'package:stretchy_header/stretchy_header.dart';

class SampleCustomHeader extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: StretchyHeader.singleChild(
        headerData: HeaderData(
          headerHeight: 200,
          backgroundColor: Colors.black54,
          blurColor: Colors.yellow,
          header: UserAccountsDrawerHeader(
            accountName: Text("Diego"),
            accountEmail: Text("twitter @diegoveloper"),
            currentAccountPicture: CircleAvatar(
              backgroundColor: Colors.red,
              child: Text("DV"),
            ),
            margin: EdgeInsets.zero,
          ),
          overlay: Align(
            alignment: Alignment.bottomRight,
            child: Material(
              color: Colors.transparent,
              child: InkResponse(
                onTap: () {
                  Scaffold.of(context).showSnackBar(
                    SnackBar(
                      content: Text('onTap'),
                    ),
                  );
                },
                child: Padding(
                  padding: EdgeInsets.all(12),
                  child: Icon(
                    Icons.fullscreen,
                    color: Colors.white,
                  ),
                ),
              ),
            ),
          ),
        ),
        child: Padding(
          padding: const EdgeInsets.all(15),
          child: Text(
            "Hello World!",
            style: TextStyle(fontSize: 45, color: Colors.white),
          ),
        ),
      ),
    );
  }
}

Sample 3 #

class SampleBottomLabel extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: StretchyHeader.singleChild(
        headerData: HeaderData(
          headerHeight: 250,
          header: Image.asset(
            "images/machu.jpg",
            fit: BoxFit.cover,
          ),
          highlightHeaderAlignment: HighlightHeaderAlignment.bottom,
          highlightHeader: Container(
            width: MediaQuery.of(context).size.width,
            decoration: BoxDecoration(
                gradient: LinearGradient(
                  colors: [
                    Colors.black54,
                    Colors.black54,
                    Colors.black26,
                    Colors.black12,
                    Colors.black12,
                  ],
                  begin: Alignment.bottomCenter,
                  end: Alignment.topCenter,
                )),
            child: Padding(
              padding: const EdgeInsets.all(15),
              child: Text(
                "Machu Picchu",
                style: TextStyle(color: Colors.white, fontSize: 22),
              ),
            ),
          ),
        ),
        child: Padding(
          padding: const EdgeInsets.all(15),
          child: Text(LONG_DESCRIPTION),
        ),
      ),
    );
  }
}

Sample 4 #

class SampleCenterWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: StretchyHeader.singleChild(
        headerData: HeaderData(
          headerHeight: 250,
          header: Image.asset(
            "images/machu.jpg",
            fit: BoxFit.cover,
          ),
          highlightHeaderAlignment: HighlightHeaderAlignment.center,
          highlightHeader: SizedBox(
            width: MediaQuery.of(context).size.width,
            child: GestureDetector(
              onTap: () {
                print("tap highlightHeader");
              },
              child: CircleAvatar(
                backgroundColor: Colors.red,
                child: Text("M"),
              ),
            ),
          ),
        ),
        child: Padding(
          padding: const EdgeInsets.all(15),
          child: Text(LONG_DESCRIPTION),
        ),
      ),
    );
  }
}

You can follow me on twitter @diegoveloper

[1.0.8] #

  • onRefresh callback was added , it works similar like the RefreshIndicator widget.
  • displacement property was added, default value is 40. if onRefresh is null then this property is ignored.

[1.0.7] #

Bugs fixed

[1.0.6] #

Add overlay widget to header. This widget will be placed on top the header container.

Can be used to add clickable items to the header bottom which doesn't prevent it from scrolling.

[1.0.5] #

  • Get rid of nested ListViews, allow list items to consume gestures [Thanks PiN73].

[1.0.4] #

  • New option to avoid blur the content when scroll. blurContent = false.

[1.0.1 - 1.0.3] #

  • Fixed an issue related to the highlightHeader (now it can detects gesture events).

[1.0.0] #

  • First release.

example/lib/main.dart

import 'package:example/long_description.dart';
import 'package:flutter/material.dart';
import 'package:stretchy_header/stretchy_header.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Stretchy',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Samples(),
    );
  }
}

class Samples extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            MaterialButton(
              onPressed: () {
                Navigator.of(context).push(MaterialPageRoute(
                  builder: (context) => SampleListView(),
                ));
              },
              child: Text("ListView"),
              color: Colors.red,
            ),
            MaterialButton(
              onPressed: () {
                Navigator.of(context).push(MaterialPageRoute(
                  builder: (context) => SampleCustomHeader(),
                ));
              },
              child: Text("Custom header"),
              color: Colors.red,
            ),
            MaterialButton(
              onPressed: () {
                Navigator.of(context).push(MaterialPageRoute(
                  builder: (context) => SampleBottomLabel(),
                ));
              },
              child: Text("Bottom label"),
              color: Colors.red,
            ),
            MaterialButton(
              onPressed: () {
                Navigator.of(context).push(MaterialPageRoute(
                  builder: (context) => SampleCenterWidget(),
                ));
              },
              child: Text("Center widget"),
              color: Colors.red,
            ),
            MaterialButton(
              onPressed: () {
                Navigator.of(context).push(MaterialPageRoute(
                  builder: (context) => SampleRefreshIndicator(),
                ));
              },
              child: Text("Refresh Indicator"),
              color: Colors.red,
            ),
          ],
        ),
      ),
    );
  }
}

class SampleListView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: StretchyHeader.listViewBuilder(
        headerData: HeaderData(
          headerHeight: 250,
          header: Image.asset(
            "images/chichen.jpg",
            fit: BoxFit.cover,
          ),
        ),
        itemCount: 15,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text("item $index"),
            onTap: () {
              final snackBar = SnackBar(
                content: Text('item $index tapped'),
              );
              Scaffold.of(context).showSnackBar(snackBar);
            },
          );
        },
      ),
    );
  }
}

class SampleCustomHeader extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: StretchyHeader.singleChild(
        headerData: HeaderData(
          headerHeight: 200,
          backgroundColor: Colors.black54,
          blurColor: Colors.yellow,
          header: UserAccountsDrawerHeader(
            accountName: Text("Diego"),
            accountEmail: Text("twitter @diegoveloper"),
            currentAccountPicture: CircleAvatar(
              backgroundColor: Colors.red,
              child: Text("DV"),
            ),
            margin: EdgeInsets.zero,
          ),
          overlay: Align(
            alignment: Alignment.bottomRight,
            child: Material(
              color: Colors.transparent,
              child: Builder(
                builder: (newContext) {
                  return InkResponse(
                    onTap: () {
                      Scaffold.of(newContext).showSnackBar(
                        SnackBar(
                          content: Text('onTap'),
                        ),
                      );
                    },
                    child: Padding(
                      padding: EdgeInsets.all(12),
                      child: Icon(
                        Icons.fullscreen,
                        color: Colors.white,
                      ),
                    ),
                  );
                },
              ),
            ),
          ),
        ),
        child: Padding(
          padding: const EdgeInsets.all(15),
          child: Text(
            "Hello World!",
            style: TextStyle(fontSize: 45, color: Colors.white),
          ),
        ),
      ),
    );
  }
}

class SampleBottomLabel extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: StretchyHeader.singleChild(
        headerData: HeaderData(
          headerHeight: 250,
          header: Image.asset(
            "images/machu.jpg",
            fit: BoxFit.cover,
          ),
          highlightHeaderAlignment: HighlightHeaderAlignment.bottom,
          highlightHeader: Container(
            width: MediaQuery.of(context).size.width,
            decoration: BoxDecoration(
                gradient: LinearGradient(
              colors: [
                Colors.black54,
                Colors.black54,
                Colors.black26,
                Colors.black12,
                Colors.black12,
              ],
              begin: Alignment.bottomCenter,
              end: Alignment.topCenter,
            )),
            child: Padding(
              padding: const EdgeInsets.all(15),
              child: Text(
                "Machu Picchu",
                style: TextStyle(color: Colors.white, fontSize: 22),
              ),
            ),
          ),
        ),
        child: Padding(
          padding: const EdgeInsets.all(15),
          child: Text(LONG_DESCRIPTION),
        ),
      ),
    );
  }
}

class SampleCenterWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: StretchyHeader.singleChild(
        headerData: HeaderData(
          headerHeight: 250,
          header: Image.asset(
            "images/machu.jpg",
            fit: BoxFit.cover,
          ),
          highlightHeaderAlignment: HighlightHeaderAlignment.center,
          highlightHeader: SizedBox(
            width: MediaQuery.of(context).size.width,
            child: GestureDetector(
              onTap: () {
                print("tap highlightHeader");
              },
              child: CircleAvatar(
                backgroundColor: Colors.red,
                child: Text("M"),
              ),
            ),
          ),
        ),
        child: Padding(
          padding: const EdgeInsets.all(15),
          child: Text(LONG_DESCRIPTION),
        ),
      ),
    );
  }
}

class SampleRefreshIndicator extends StatefulWidget {
  @override
  _SampleRefreshIndicatorState createState() => _SampleRefreshIndicatorState();
}

class _SampleRefreshIndicatorState extends State<SampleRefreshIndicator> {
  bool isLoading = false;
  bool numbers = true;

  void _loadFakeData() async {
    setState(() {
      isLoading = true;
    });

    await Future.delayed(Duration(seconds: 3));
    numbers = !numbers;
    setState(() {
      isLoading = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          StretchyHeader.listViewBuilder(
            onRefresh: () {
              _loadFakeData();
            },
            headerData: HeaderData(
              headerHeight: 250,
              header: Image.asset(
                "images/machu.jpg",
                fit: BoxFit.cover,
              ),
            ),
            itemCount: 15,
            itemBuilder: (context, index) {
              return ListTile(
                title: numbers
                    ? Text("item $index")
                    : Container(
                        height: 10,
                        width: 10,
                        color:
                            Colors.primaries[index % Colors.primaries.length],
                      ),
                onTap: () {
                  final snackBar = SnackBar(
                    content: Text('item $index tapped'),
                  );
                  Scaffold.of(context).showSnackBar(snackBar);
                },
              );
            },
          ),
          if (isLoading) _buildLoadingWidget()
        ],
      ),
    );
  }

  Widget _buildLoadingWidget() {
    return Container(
      color: Colors.black54,
      child: Center(
        child: CircularProgressIndicator(),
      ),
    );
  }
}

Use this package as a library

1. Depend on it

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


dependencies:
  stretchy_header: ^1.0.8

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:stretchy_header/stretchy_header.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
79
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
90
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

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.3.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