Skip to content

Commit

Permalink
Fixes #7
Browse files Browse the repository at this point in the history
  • Loading branch information
letsar committed Jul 18, 2018
1 parent 116ab18 commit 6c4a6f7
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 72 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.3.1
### Fixed
* Hit test implementation (https://github.com/letsar/flutter_sticky_header/issues/7)

## 0.3.0
### Added
* `SliverStickyHeaderState` class. This state has `scrollPercentage` and `isPinned` properties and it's passed to the `SliverStickyHeaderBuilder` when it changes.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ In the `pubspec.yaml` of your flutter project, add the following dependency:
```yaml
dependencies:
...
flutter_sticky_header: "^0.3.0"
flutter_sticky_header: "^0.3.1"
```
In your library add the following import:
Expand Down
151 changes: 91 additions & 60 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,29 @@ class MyApp extends StatelessWidget {
class MainScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new SimpleScaffold(
title: 'Flutter Sticky Header example',
child: new Builder(builder: (BuildContext context) {
return new CustomScrollView(slivers: _buildSlivers(context));
}),
);
}

List<Widget> _buildSlivers(BuildContext context) {
List<Widget> slivers = new List<Widget>();

//slivers.add(_buildExample());
//slivers.add(_buildBuilderExample());
int i = 0;
slivers.addAll(_buildHeaderBuilderLists(i, i += 5));
slivers.addAll(_buildLists(i, i += 3));
slivers.addAll(_buildGrids(i, i += 3));
slivers.addAll(_buildSideHeaderGrids(i, i += 3));
slivers.addAll(_buildHeaderBuilderLists(i, i += 5));

return new SimpleScaffold(
title: 'Flutter Sticky Header example',
child: new CustomScrollView(slivers: slivers),
);
slivers.addAll(_buildHeaderBuilderLists(context, i, i += 5));
slivers.addAll(_buildLists(context, i, i += 3));
slivers.addAll(_buildGrids(context, i, i += 3));
slivers.addAll(_buildSideHeaderGrids(context, i, i += 3));
slivers.addAll(_buildHeaderBuilderLists(context, i, i += 5));
return slivers;
}

List<Widget> _buildLists(int firstIndex, int count) {
List<Widget> _buildLists(BuildContext context, int firstIndex, int count) {
return List.generate(count, (sliverIndex) {
sliverIndex += firstIndex;
return new SliverStickyHeader(
Expand All @@ -56,11 +61,13 @@ class MainScreen extends StatelessWidget {
});
}

List<Widget> _buildHeaderBuilderLists(int firstIndex, int count) {
List<Widget> _buildHeaderBuilderLists(
BuildContext context, int firstIndex, int count) {
return List.generate(count, (sliverIndex) {
sliverIndex += firstIndex;
return new SliverStickyHeaderBuilder(
builder: (context, state) => _buildAnimatedHeader(sliverIndex, state),
builder: (context, state) =>
_buildAnimatedHeader(context, sliverIndex, state),
sliver: new SliverList(
delegate: new SliverChildBuilderDelegate(
(context, i) => new ListTile(
Expand All @@ -76,7 +83,7 @@ class MainScreen extends StatelessWidget {
});
}

List<Widget> _buildGrids(int firstIndex, int count) {
List<Widget> _buildGrids(BuildContext context, int firstIndex, int count) {
return List.generate(count, (sliverIndex) {
sliverIndex += firstIndex;
return new SliverStickyHeader(
Expand All @@ -85,19 +92,23 @@ class MainScreen extends StatelessWidget {
gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, crossAxisSpacing: 4.0, mainAxisSpacing: 4.0),
delegate: new SliverChildBuilderDelegate(
(context, i) => new GridTile(
child: Card(
child: new Container(
color: Colors.green,
(context, i) => GestureDetector(
onTap: () => Scaffold.of(context).showSnackBar(
new SnackBar(content: Text('Grid tile #$i'))),
child: new GridTile(
child: Card(
child: new Container(
color: Colors.green,
),
),
),
footer: new Container(
color: Colors.white.withOpacity(0.5),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: new Text(
'Grid tile #$i',
style: const TextStyle(color: Colors.black),
footer: new Container(
color: Colors.white.withOpacity(0.5),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: new Text(
'Grid tile #$i',
style: const TextStyle(color: Colors.black),
),
),
),
),
Expand All @@ -109,12 +120,13 @@ class MainScreen extends StatelessWidget {
});
}

List<Widget> _buildSideHeaderGrids(int firstIndex, int count) {
List<Widget> _buildSideHeaderGrids(
BuildContext context, int firstIndex, int count) {
return List.generate(count, (sliverIndex) {
sliverIndex += firstIndex;
return new SliverStickyHeader(
overlapsContent: true,
header: _buildSideHeader(sliverIndex),
header: _buildSideHeader(context, sliverIndex),
sliver: new SliverPadding(
padding: new EdgeInsets.only(left: 60.0),
sliver: new SliverGrid(
Expand All @@ -124,19 +136,23 @@ class MainScreen extends StatelessWidget {
mainAxisSpacing: 4.0,
childAspectRatio: 1.0),
delegate: new SliverChildBuilderDelegate(
(context, i) => new GridTile(
child: Card(
child: new Container(
color: Colors.orange,
(context, i) => GestureDetector(
onTap: () => Scaffold.of(context).showSnackBar(
new SnackBar(content: Text('Grid tile #$i'))),
child: new GridTile(
child: Card(
child: new Container(
color: Colors.orange,
),
),
),
footer: new Container(
color: Colors.white.withOpacity(0.5),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: new Text(
'Grid tile #$i',
style: const TextStyle(color: Colors.black),
footer: new Container(
color: Colors.white.withOpacity(0.5),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: new Text(
'Grid tile #$i',
style: const TextStyle(color: Colors.black),
),
),
),
),
Expand All @@ -162,30 +178,45 @@ class MainScreen extends StatelessWidget {
);
}

Widget _buildSideHeader(int index, {String text}) {
return new Container(
height: 60.0,
color: Colors.transparent,
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: new CircleAvatar(
backgroundColor: Colors.orangeAccent,
foregroundColor: Colors.white,
child: new Text('$index'),
Widget _buildSideHeader(BuildContext context, int index, {String text}) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0),
child: Align(
alignment: Alignment.centerLeft,
child: new SizedBox(
height: 44.0,
width: 44.0,
child: GestureDetector(
onTap: () => Scaffold
.of(context)
.showSnackBar(new SnackBar(content: Text('$index'))),
child: new CircleAvatar(
backgroundColor: Colors.orangeAccent,
foregroundColor: Colors.white,
child: new Text('$index'),
),
),
),
),
);
}

Widget _buildAnimatedHeader(int index, SliverStickyHeaderState state) {
return new Container(
height: 60.0,
color: (state.isPinned ? Colors.pink : Colors.lightBlue)
.withOpacity(1.0 - state.scrollPercentage),
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: new Text(
'Header #$index',
style: const TextStyle(color: Colors.white),
Widget _buildAnimatedHeader(
BuildContext context, int index, SliverStickyHeaderState state) {
return GestureDetector(
onTap: () => Scaffold
.of(context)
.showSnackBar(new SnackBar(content: Text('$index'))),
child: new Container(
height: 60.0,
color: (state.isPinned ? Colors.pink : Colors.lightBlue)
.withOpacity(1.0 - state.scrollPercentage),
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: new Text(
'Header #$index',
style: const TextStyle(color: Colors.white),
),
),
);
}
Expand Down
25 changes: 18 additions & 7 deletions lib/src/rendering/sliver_sticky_header.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ class RenderSliverStickyHeader extends RenderSliver with RenderSliverHelpers {
}

SliverStickyHeaderState _oldState;

double _headerExtent;
bool _isPinned;

bool get overlapsContent => _overlapsContent;
bool _overlapsContent;
Expand Down Expand Up @@ -222,14 +222,17 @@ class RenderSliverStickyHeader extends RenderSliver with RenderSliverHelpers {
constraints.scrollOffset -
(overlapsContent ? _headerExtent : 0.0));

_isPinned = constraints.scrollOffset > 0.0 ||
constraints.remainingPaintExtent ==
constraints.viewportMainAxisExtent;

// second layout if scroll percentage changed and header is a RenderStickyHeaderLayoutBuilder.
if (header is RenderStickyHeaderLayoutBuilder) {
double scrollPercentage =
(headerPosition.abs() / _headerExtent).clamp(0.0, 1.0);
bool isPinned = constraints.scrollOffset > 0.0 || constraints.remainingPaintExtent == constraints.viewportMainAxisExtent;

SliverStickyHeaderState state =
new SliverStickyHeaderState(scrollPercentage, isPinned);
new SliverStickyHeaderState(scrollPercentage, _isPinned);
if (_oldState != state) {
_oldState = state;
header.layout(
Expand Down Expand Up @@ -267,8 +270,15 @@ class RenderSliverStickyHeader extends RenderSliver with RenderSliverHelpers {
assert(geometry.hitTestExtent > 0.0);
if (header != null && mainAxisPosition <= _headerExtent) {
return hitTestBoxChild(result, header,
mainAxisPosition: mainAxisPosition,
crossAxisPosition: crossAxisPosition);
mainAxisPosition: mainAxisPosition,
crossAxisPosition: crossAxisPosition) ||
(_overlapsContent &&
child != null &&
child.geometry.hitTestExtent > 0.0 &&
child.hitTest(result,
mainAxisPosition:
mainAxisPosition - childMainAxisPosition(child),
crossAxisPosition: crossAxisPosition));
} else if (child != null && child.geometry.hitTestExtent > 0.0) {
return child.hitTest(result,
mainAxisPosition: mainAxisPosition - childMainAxisPosition(child),
Expand All @@ -279,9 +289,10 @@ class RenderSliverStickyHeader extends RenderSliver with RenderSliverHelpers {

@override
double childMainAxisPosition(RenderObject child) {
if (child == header) return -constraints.scrollOffset;
if (child == header) return _isPinned ? 0.0 : -constraints.scrollOffset;
if (child == this.child)
return calculatePaintOffset(constraints, from: 0.0, to: _headerExtent);
return calculatePaintOffset(constraints,
from: 0.0, to: headerLogicalExtent);
return null;
}

Expand Down
6 changes: 3 additions & 3 deletions lib/src/widgets/sliver_sticky_header.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ typedef Widget SliverStickyHeaderWidgetBuilder(
@immutable
class SliverStickyHeaderState {
const SliverStickyHeaderState(
this.scrollPercentage,
this.isPinned,
) : assert(scrollPercentage != null),
this.scrollPercentage,
this.isPinned,
) : assert(scrollPercentage != null),
assert(isPinned != null);

final double scrollPercentage;
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: flutter_sticky_header
description: Flutter implementation of sticky header
version: 0.3.0
version: 0.3.1
author: Romain Rastel <[email protected]>
homepage: https://github.com/letsar/flutter_sticky_header

Expand Down

0 comments on commit 6c4a6f7

Please sign in to comment.