Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a callback that handles the changes in the state of a sticky header such as "onPinned" #92

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Prev Previous commit
Next Next commit
Add the activity handler
fujidaiti committed Jun 25, 2023
commit 07f5a7c6cfc909d032640c9e3c7237e867709715
34 changes: 34 additions & 0 deletions lib/src/rendering/sliver_sticky_header.dart
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ import 'dart:math' as math;

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_sticky_header/flutter_sticky_header.dart';
import 'package:value_layout_builder/value_layout_builder.dart';

@@ -16,13 +17,17 @@ class RenderSliverStickyHeader extends RenderSliver with RenderSliverHelpers {
bool overlapsContent: false,
bool sticky: true,
StickyHeaderController? controller,
this.activityHandler,
}) : _overlapsContent = overlapsContent,
_sticky = sticky,
_controller = controller {
this.header = header as RenderBox?;
this.child = child;
}

SliverStickyHeaderActivityHandler? activityHandler;
SliverStickyHeaderActivity? _lastReportedActivity;

SliverStickyHeaderState? _oldState;
double? _headerExtent;
late bool _isPinned;
@@ -261,6 +266,9 @@ class RenderSliverStickyHeader extends RenderSliver with RenderSliverHelpers {
controller?.stickyHeaderScrollOffset =
constraints.precedingScrollExtent;
}

_tryNotifyActivity(headerScrollRatio);

// second layout if scroll percentage changed and header is a
// RenderStickyHeaderLayoutBuilder.
if (header is RenderConstrainedLayoutBuilder<
@@ -300,6 +308,32 @@ class RenderSliverStickyHeader extends RenderSliver with RenderSliverHelpers {
}
}

void _tryNotifyActivity(double headerScrollRatio) {
final SliverStickyHeaderActivity location;
if (_isPinned) {
if (headerScrollRatio >= 1) {
location = SliverStickyHeaderActivity.pushed;
} else if (headerScrollRatio > 0) {
location = SliverStickyHeaderActivity.settling;
} else {
location = SliverStickyHeaderActivity.pinned;
}
} else {
location = SliverStickyHeaderActivity.unpinned;
}

if (activityHandler != null &&
_lastReportedActivity != null &&
location != _lastReportedActivity) {
WidgetsBinding.instance.scheduleTask(
() => activityHandler?.call(location),
Priority.touch,
);
}

_lastReportedActivity = location;
}

@override
bool hitTestChildren(SliverHitTestResult result,
{required double mainAxisPosition, required double crossAxisPosition}) {
12 changes: 11 additions & 1 deletion lib/src/widgets/sliver_sticky_header.dart
Original file line number Diff line number Diff line change
@@ -134,6 +134,9 @@ class SliverStickyHeaderState {
}
}

typedef SliverStickyHeaderActivityHandler = void Function(
SliverStickyHeaderActivity activity);

enum SliverStickyHeaderActivity {
pushed,
unpinned,
@@ -162,6 +165,7 @@ class SliverStickyHeader extends RenderObjectWidget {
this.overlapsContent: false,
this.sticky = true,
this.controller,
this.activityHandler,
}) : super(key: key);

/// Creates a widget that builds the header of a [SliverStickyHeader]
@@ -178,6 +182,7 @@ class SliverStickyHeader extends RenderObjectWidget {
bool overlapsContent: false,
bool sticky = true,
StickyHeaderController? controller,
SliverStickyHeaderActivityHandler? activityHandler,
}) : this(
key: key,
header: ValueLayoutBuilder<SliverStickyHeaderState>(
@@ -188,6 +193,7 @@ class SliverStickyHeader extends RenderObjectWidget {
overlapsContent: overlapsContent,
sticky: sticky,
controller: controller,
activityHandler: activityHandler,
);

/// The header to display before the sliver.
@@ -210,12 +216,15 @@ class SliverStickyHeader extends RenderObjectWidget {
/// will be used.
final StickyHeaderController? controller;

final SliverStickyHeaderActivityHandler? activityHandler;

@override
RenderSliverStickyHeader createRenderObject(BuildContext context) {
return RenderSliverStickyHeader(
overlapsContent: overlapsContent,
sticky: sticky,
controller: controller ?? DefaultStickyHeaderController.of(context),
activityHandler: activityHandler,
);
}

@@ -231,7 +240,8 @@ class SliverStickyHeader extends RenderObjectWidget {
renderObject
..overlapsContent = overlapsContent
..sticky = sticky
..controller = controller ?? DefaultStickyHeaderController.of(context);
..controller = controller ?? DefaultStickyHeaderController.of(context)
..activityHandler = activityHandler;
}
}