From 394cca0a749dae5532017ce26515b44f2b5b8e9f Mon Sep 17 00:00:00 2001 From: Wayne <974815768@qq.com> Date: Thu, 14 Dec 2023 13:56:00 +0800 Subject: [PATCH 1/3] Added headerSpacing. --- lib/sticky_headers/render.dart | 15 +++++++++++++-- lib/sticky_headers/widget.dart | 17 ++++++++++++++--- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/lib/sticky_headers/render.dart b/lib/sticky_headers/render.dart index f83e58f..77cbc90 100644 --- a/lib/sticky_headers/render.dart +++ b/lib/sticky_headers/render.dart @@ -27,16 +27,19 @@ class RenderStickyHeader extends RenderBox RenderStickyHeaderCallback? _callback; ScrollPosition _scrollPosition; bool _overlapHeaders; + double _headerSpacing; RenderStickyHeader({ required ScrollPosition scrollPosition, RenderStickyHeaderCallback? callback, bool overlapHeaders = false, + double headerSpacing = 0.0, RenderBox? header, RenderBox? content, }) : _scrollPosition = scrollPosition, _callback = callback, - _overlapHeaders = overlapHeaders { + _overlapHeaders = overlapHeaders, + _headerSpacing = headerSpacing { if (content != null) add(content); if (header != null) add(header); } @@ -70,6 +73,14 @@ class RenderStickyHeader extends RenderBox markNeedsLayout(); } + set headerSpacing(double newValue) { + if (_headerSpacing == newValue) { + return; + } + _headerSpacing = newValue; + markNeedsLayout(); + } + @override void attach(PipelineOwner owner) { super.attach(owner); @@ -135,7 +146,7 @@ class RenderStickyHeader extends RenderBox final scrollBox = _scrollPosition.context.notificationContext!.findRenderObject(); if (scrollBox?.attached ?? false) { try { - return localToGlobal(Offset.zero, ancestor: scrollBox).dy; + return localToGlobal(Offset(0, -(_headerSpacing)), ancestor: scrollBox).dy; } catch (e) { // ignore and fall-through and return 0.0 } diff --git a/lib/sticky_headers/widget.dart b/lib/sticky_headers/widget.dart index ca639ef..8d4ca7d 100644 --- a/lib/sticky_headers/widget.dart +++ b/lib/sticky_headers/widget.dart @@ -33,6 +33,7 @@ class StickyHeader extends MultiChildRenderObjectWidget { Key? key, required this.header, required this.content, + this.headerSpacing = 0.0, this.overlapHeaders = false, this.controller, this.callback, @@ -48,6 +49,9 @@ class StickyHeader extends MultiChildRenderObjectWidget { /// Content to be shown below the header. final Widget content; + /// Spacing between sticky header and start position. + final double headerSpacing; + /// If true, the header will overlap the Content. final bool overlapHeaders; @@ -60,21 +64,23 @@ class StickyHeader extends MultiChildRenderObjectWidget { @override RenderStickyHeader createRenderObject(BuildContext context) { - final scrollPosition = controller?.position ?? Scrollable.of(context)!.position; + final scrollPosition = controller?.position ?? Scrollable.of(context).position; return RenderStickyHeader( scrollPosition: scrollPosition, callback: callback, overlapHeaders: overlapHeaders, + headerSpacing: headerSpacing, ); } @override void updateRenderObject(BuildContext context, RenderStickyHeader renderObject) { - final scrollPosition = controller?.position ?? Scrollable.of(context)!.position; + final scrollPosition = controller?.position ?? Scrollable.of(context).position; renderObject ..scrollPosition = scrollPosition ..callback = callback - ..overlapHeaders = overlapHeaders; + ..overlapHeaders = overlapHeaders + ..headerSpacing = headerSpacing; } } @@ -91,6 +97,7 @@ class StickyHeaderBuilder extends StatefulWidget { Key? key, required this.builder, required this.content, + this.headerSpacing = 0.0, this.overlapHeaders = false, this.controller, }) : super(key: key); @@ -102,6 +109,9 @@ class StickyHeaderBuilder extends StatefulWidget { /// Content to be shown below the header. final Widget content; + /// Spacing between sticky header and start position. + final double headerSpacing; + /// If true, the header will overlap the Content. final bool overlapHeaders; @@ -119,6 +129,7 @@ class _StickyHeaderBuilderState extends State { Widget build(BuildContext context) { return StickyHeader( overlapHeaders: widget.overlapHeaders, + headerSpacing: widget.headerSpacing, header: LayoutBuilder( builder: (context, _) => widget.builder(context, _stuckAmount ?? 0.0), ), From 70fc46da9a4d61c2792b85ec033484405b04067c Mon Sep 17 00:00:00 2001 From: Wayne <974815768@qq.com> Date: Mon, 19 Feb 2024 09:23:40 +0800 Subject: [PATCH 2/3] Update stuckAmount to nullable --- example/lib/main.dart | 8 ++++---- lib/sticky_headers/render.dart | 2 +- lib/sticky_headers/widget.dart | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index ec66dac..9ad2c79 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -130,8 +130,8 @@ class Example2 extends StatelessWidget { itemBuilder: (context, index) { return StickyHeaderBuilder( controller: controller, // Optional - builder: (BuildContext context, double stuckAmount) { - stuckAmount = 1.0 - stuckAmount.clamp(0.0, 1.0); + builder: (BuildContext context, double? stuckAmount) { + stuckAmount = 1.0 - (stuckAmount ?? 0.0).clamp(0.0, 1.0); return Container( height: 50.0, color: Color.lerp(Colors.blue[700], Colors.red[700], stuckAmount), @@ -201,8 +201,8 @@ class Example3 extends StatelessWidget { return StickyHeaderBuilder( overlapHeaders: true, controller: controller, // Optional - builder: (BuildContext context, double stuckAmount) { - stuckAmount = 1.0 - stuckAmount.clamp(0.0, 1.0); + builder: (BuildContext context, double? stuckAmount) { + stuckAmount = 1.0 - (stuckAmount ?? 0.0).clamp(0.0, 1.0); return Container( height: 50.0, color: Colors.grey.shade900.withOpacity(0.6 + stuckAmount * 0.4), diff --git a/lib/sticky_headers/render.dart b/lib/sticky_headers/render.dart index 77cbc90..c3b843f 100644 --- a/lib/sticky_headers/render.dart +++ b/lib/sticky_headers/render.dart @@ -11,7 +11,7 @@ import 'package:flutter/widgets.dart'; /// Called every layout to provide the amount of stickyness a header is in. /// This lets the widgets animate their content and provide feedback. /// -typedef RenderStickyHeaderCallback = void Function(double stuckAmount); +typedef RenderStickyHeaderCallback = void Function(double? stuckAmount); /// RenderObject for StickyHeader widget. /// diff --git a/lib/sticky_headers/widget.dart b/lib/sticky_headers/widget.dart index 8d4ca7d..fa9a03b 100644 --- a/lib/sticky_headers/widget.dart +++ b/lib/sticky_headers/widget.dart @@ -18,7 +18,7 @@ import './render.dart'; /// -1.0 >= value >= 0.0: past stuck /// ``` /// -typedef StickyHeaderWidgetBuilder = Widget Function(BuildContext context, double stuckAmount); +typedef StickyHeaderWidgetBuilder = Widget Function(BuildContext context, double? stuckAmount); /// Stick Header Widget /// @@ -131,11 +131,11 @@ class _StickyHeaderBuilderState extends State { overlapHeaders: widget.overlapHeaders, headerSpacing: widget.headerSpacing, header: LayoutBuilder( - builder: (context, _) => widget.builder(context, _stuckAmount ?? 0.0), + builder: (context, _) => widget.builder(context, _stuckAmount), ), content: widget.content, controller: widget.controller, - callback: (double stuckAmount) { + callback: (double? stuckAmount) { if (_stuckAmount != stuckAmount) { _stuckAmount = stuckAmount; WidgetsBinding.instance.endOfFrame.then((_) { From 1fedce3309b191ff67e8586e6dd6297e195349c5 Mon Sep 17 00:00:00 2001 From: Wayne <974815768@qq.com> Date: Fri, 15 Mar 2024 09:58:44 +0800 Subject: [PATCH 3/3] Update stuckAmount callback. --- lib/sticky_headers/render.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sticky_headers/render.dart b/lib/sticky_headers/render.dart index c3b843f..c2c798b 100644 --- a/lib/sticky_headers/render.dart +++ b/lib/sticky_headers/render.dart @@ -136,7 +136,7 @@ class RenderStickyHeader extends RenderBox headerParentData.offset = Offset(0.0, max(0.0, min(-stuckOffset, maxOffset))); // report to widget how much the header is stuck. - if (_callback != null) { + if (_callback != null && stuckOffset != 0) { final stuckAmount = max(min(headerHeight, stuckOffset), -headerHeight) / headerHeight; _callback!(stuckAmount); }