sticky_headers 0.1.4

  • README.md
  • CHANGELOG.md
  • Example
  • Installing
  • Versions
  • new50

Flutter Sticky Headers

pub package

Lets you place headers on scrollable content that will stick to the top of the container whilst the content is scrolled.

Usage

You can place a StickyHeader or StickyHeaderBuilder inside any scrollable content, such as: ListView, GridView, CustomScrollView, SingleChildScrollView or similar.

Depend on it:

dependencies:
  sticky_headers: "^0.1.4"

Import it:

import 'package:sticky_headers/sticky_headers.dart';

Use it:

class Example extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new ListView.builder(itemBuilder: (context, index) {
      return new StickyHeader(
        header: new Container(
          height: 50.0,
          color: Colors.blueGrey[700],
          padding: new EdgeInsets.symmetric(horizontal: 16.0),
          alignment: Alignment.centerLeft,
          child: new Text('Header #$index',
            style: const TextStyle(color: Colors.white),
          ),
        ),
        content: new Container(
          child: new Image.network(imageForIndex(index), fit: BoxFit.cover,
            width: double.infinity, height: 200.0),
        ),
      );
    });
  }
}

Examples

Example 1 - Headers and Content

Demo 1

Example 2 - Animated Headers with Content

Demo 2

Example 3 - Headers overlapping the Content

Demo 3

Bugs/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.

Changelog

0.1.0

  • Initial version release

0.1.1 ~ 0.1.4

  • Improved readme, docs and formatting.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:meta/meta.dart';
import 'package:sticky_headers/sticky_headers.dart';

import './images.dart';

void main() => runApp(new ExampleApp());

class ExampleApp extends StatelessWidget {
	@override
	Widget build(BuildContext context) {
		return new MaterialApp(
			title: 'Sticky Headers Example',
			theme: new ThemeData(
				primarySwatch: Colors.blueGrey,
			),
			home: new MainScreen(),
		);
	}
}

class MainScreen extends StatelessWidget {
	@override
	Widget build(BuildContext context) {
		return new ScaffoldWrapper(
			title: 'Sticky Headers Example',
			child: new ListView(
				children: ListTile.divideTiles(
					context: context,
					tiles: <Widget>[
						new ListTile(
							title: const Text('Example 1 - Headers and Content'),
							onTap: () => navigateTo(context, (context) => new Example1()),
						),
						new ListTile(
							title: const Text('Example 2 - Animated Headers with Content'),
							onTap: () => navigateTo(context, (context) => new Example2()),
						),
						new ListTile(
							title: const Text('Example 3 - Headers overlapping the Content'),
							onTap: () => navigateTo(context, (context) => new Example3()),
						),
					],
				).toList(growable: false),
			),
		);
	}

	navigateTo(BuildContext context, builder(BuildContext context)) {
		Navigator.of(context).push(new MaterialPageRoute(builder: builder));
	}
}

class Example1 extends StatelessWidget {
	@override
	Widget build(BuildContext context) {
		return new ScaffoldWrapper(
			title: 'Example 1',
			child: new ListView.builder(itemBuilder: (context, index) {
				return new Material(
					color: Colors.grey[300],
					child: new StickyHeader(
						header: new Container(
							height: 50.0,
							color: Colors.blueGrey[700],
							padding: new EdgeInsets.symmetric(horizontal: 16.0),
							alignment: Alignment.centerLeft,
							child: new Text('Header #$index',
								style: const TextStyle(color: Colors.white),
							),
						),
						content: new Container(
							child: new Image.network(imageForIndex(index), fit: BoxFit.cover,
								width: double.infinity, height: 200.0),
						),
					),
				);
			}),
		);
	}

	String imageForIndex(int index) {
		return Images.imageThumbUrls[index % Images.imageThumbUrls.length];
	}
}

class Example2 extends StatelessWidget {
	@override
	Widget build(BuildContext context) {
		return new ScaffoldWrapper(
			title: 'Example 2',
			child: new ListView.builder(itemBuilder: (context, index) {
				return new Material(
					color: Colors.grey[300],
					child: new StickyHeaderBuilder(
						builder: (BuildContext context, double stuckAmount) {
							stuckAmount = 1.0 - stuckAmount.clamp(0.0, 1.0);
							return new Container(
								height: 50.0,
								color: Color.lerp(Colors.blue[700], Colors.red[700], stuckAmount),
								padding: new EdgeInsets.symmetric(horizontal: 16.0),
								alignment: Alignment.centerLeft,
								child: new Row(
									children: <Widget>[
										new Expanded(
											child: new Text('Header #$index',
												style: const TextStyle(color: Colors.white),
											),
										),
										new Offstage(
											offstage: stuckAmount <= 0.0,
											child: new Opacity(
												opacity: stuckAmount,
												child: new IconButton(
													icon: new Icon(Icons.favorite, color: Colors.white),
													onPressed: () =>
														Scaffold.of(context).showSnackBar(
															new SnackBar(content: new Text('Favorite #$index'))
														),
												),
											),
										),
									],
								),
							);
						},
						content: new Container(
							child: new Image.network(imageForIndex(index), fit: BoxFit.cover,
								width: double.infinity, height: 200.0),
						),
					),
				);
			}),
		);
	}

	String imageForIndex(int index) {
		return Images.imageThumbUrls[index % Images.imageThumbUrls.length];
	}
}

class Example3 extends StatelessWidget {
	@override
	Widget build(BuildContext context) {
		return new ScaffoldWrapper(
			title: 'Example 3',
			child: new ListView.builder(itemBuilder: (context, index) {
				return new Material(
					color: Colors.grey[300],
					child: new StickyHeaderBuilder(
						overlapHeaders: true,
						builder: (BuildContext context, double stuckAmount) {
							stuckAmount = 1.0 - stuckAmount.clamp(0.0, 1.0);
							return new Container(
								height: 50.0,
								color: Colors.grey[900].withOpacity(0.6 + stuckAmount * 0.4),
								padding: new EdgeInsets.symmetric(horizontal: 16.0),
								alignment: Alignment.centerLeft,
								child: new Text('Header #$index',
									style: const TextStyle(color: Colors.white),
								),
							);
						},
						content: new Container(
							child: new Image.network(imageForIndex(index), fit: BoxFit.cover,
								width: double.infinity, height: 200.0),
						),
					),
				);
			}),
		);
	}

	String imageForIndex(int index) {
		return Images.imageThumbUrls[index % Images.imageThumbUrls.length];
	}
}

class ScaffoldWrapper extends StatelessWidget {
	final Widget child;
	final String title;

	const ScaffoldWrapper({
		Key key,
		@required this.title,
		@required this.child,
	}) : super(key: key);

	@override
	Widget build(BuildContext context) {
		return new Scaffold(
			appBar: new PreferredSize(
				preferredSize: new Size.fromHeight(kToolbarHeight),
				child: new Hero(
					tag: 'app_bar',
					child: new AppBar(
						title: new Text(title),
						elevation: 0.0,
					),
				),
			),
			body: child,
		);
	}
}

Use this package as a library

1. Depend on it

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


dependencies:
  sticky_headers: "^0.1.4"

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter packages get

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

3. Import it

Now in your Dart code, you can use:


      import 'package:sticky_headers/sticky_headers.dart';
  
Version Uploaded Documentation Archive
0.1.4 May 12, 2018 Go to the documentation of sticky_headers 0.1.4 Download sticky_headers 0.1.4 archive
0.1.3 May 12, 2018 Go to the documentation of sticky_headers 0.1.3 Download sticky_headers 0.1.3 archive
0.1.2 May 12, 2018 Go to the documentation of sticky_headers 0.1.2 Download sticky_headers 0.1.2 archive
0.1.1 May 12, 2018 Go to the documentation of sticky_headers 0.1.1 Download sticky_headers 0.1.1 archive
0.1.0 May 12, 2018 Go to the documentation of sticky_headers 0.1.0 Download sticky_headers 0.1.0 archive

Analysis

We analyzed this package on May 22, 2018, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.0.0-dev.54.0
  • pana: 0.11.1
  • Flutter: 0.4.4

Scores

Popularity:
Describes how popular the package is relative to other packages. [more]
0 / 100
Health:
Code health derived from static analysis. [more]
99 / 100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100 / 100
Overall score:
Weighted score of the above. [more]
50
Learn more about scoring.

Platforms

Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

Suggestions

  • Package is pre-v1 release.

    While there is nothing inherently wrong with versions of 0.*.*, it usually means that the author is still experimenting with the general direction API.

  • Fix analysis and formatting issues.

    Analysis or formatting checks reported 2 hints.

    Run flutter format to format lib/sticky_headers/render.dart.

    Run flutter format to format lib/sticky_headers/widget.dart.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.0.0-dev.28.0 <3.0.0
flutter 0.0.0
meta ^1.1.2 1.1.5
Transitive dependencies
collection 1.14.6 1.14.9
sky_engine 0.0.99
typed_data 1.1.5
vector_math 2.0.6 2.0.7
Dev dependencies
flutter_test