From 11a34626f863ff9a071e327578e12a94fedab12c Mon Sep 17 00:00:00 2001 From: jaap aarts Date: Thu, 26 Jan 2023 13:21:25 +0100 Subject: [PATCH 1/2] Fix header not sticking in reverse direction --- lib/sticky_headers/render.dart | 56 +++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/lib/sticky_headers/render.dart b/lib/sticky_headers/render.dart index f83e58f..4b63764 100644 --- a/lib/sticky_headers/render.dart +++ b/lib/sticky_headers/render.dart @@ -28,6 +28,8 @@ class RenderStickyHeader extends RenderBox ScrollPosition _scrollPosition; bool _overlapHeaders; + double headerHeight = 0.0; + RenderStickyHeader({ required ScrollPosition scrollPosition, RenderStickyHeaderCallback? callback, @@ -100,7 +102,7 @@ class RenderStickyHeader extends RenderBox _headerBox.layout(childConstraints, parentUsesSize: true); _contentBox.layout(childConstraints, parentUsesSize: true); - final headerHeight = roundToNearestPixel(_headerBox.size.height); + headerHeight = roundToNearestPixel(_headerBox.size.height); final contentHeight = roundToNearestPixel(_contentBox.size.height); // determine size of ourselves based on content widget @@ -108,31 +110,21 @@ class RenderStickyHeader extends RenderBox max(constraints.minWidth, _contentBox.size.width), ); final height = constraints.constrainHeight( - max(constraints.minHeight, _overlapHeaders ? contentHeight : headerHeight + contentHeight), + max(constraints.minHeight, + _overlapHeaders ? contentHeight : headerHeight + contentHeight), ); size = Size(width, height); // place content underneath header - final contentParentData = _contentBox.parentData as MultiChildLayoutParentData; - contentParentData.offset = Offset(0.0, _overlapHeaders ? 0.0 : headerHeight); - - // determine by how much the header should be stuck to the top - final double stuckOffset = roundToNearestPixel(determineStuckOffset()); - - // place header over content relative to scroll offset - final double maxOffset = height - headerHeight; - final headerParentData = _headerBox.parentData as MultiChildLayoutParentData; - headerParentData.offset = Offset(0.0, max(0.0, min(-stuckOffset, maxOffset))); - - // report to widget how much the header is stuck. - if (_callback != null) { - final stuckAmount = max(min(headerHeight, stuckOffset), -headerHeight) / headerHeight; - _callback!(stuckAmount); - } + final contentParentData = + _contentBox.parentData as MultiChildLayoutParentData; + contentParentData.offset = + Offset(0.0, _overlapHeaders ? 0.0 : headerHeight); } double determineStuckOffset() { - final scrollBox = _scrollPosition.context.notificationContext!.findRenderObject(); + final scrollBox = + _scrollPosition.context.notificationContext!.findRenderObject(); if (scrollBox?.attached ?? false) { try { return localToGlobal(Offset.zero, ancestor: scrollBox).dy; @@ -165,14 +157,16 @@ class RenderStickyHeader extends RenderBox double computeMinIntrinsicHeight(double width) { return _overlapHeaders ? _contentBox.getMinIntrinsicHeight(width) - : (_headerBox.getMinIntrinsicHeight(width) + _contentBox.getMinIntrinsicHeight(width)); + : (_headerBox.getMinIntrinsicHeight(width) + + _contentBox.getMinIntrinsicHeight(width)); } @override double computeMaxIntrinsicHeight(double width) { return _overlapHeaders ? _contentBox.getMaxIntrinsicHeight(width) - : (_headerBox.getMaxIntrinsicHeight(width) + _contentBox.getMaxIntrinsicHeight(width)); + : (_headerBox.getMaxIntrinsicHeight(width) + + _contentBox.getMaxIntrinsicHeight(width)); } @override @@ -182,7 +176,8 @@ class RenderStickyHeader extends RenderBox @override bool hitTestChildren(HitTestResult result, {required Offset position}) { - return defaultHitTestChildren(result as BoxHitTestResult, position: position); + return defaultHitTestChildren(result as BoxHitTestResult, + position: position); } @override @@ -190,6 +185,23 @@ class RenderStickyHeader extends RenderBox @override void paint(PaintingContext context, Offset offset) { + // determine by how much the header should be stuck to the top + final double stuckOffset = roundToNearestPixel(determineStuckOffset()); + + // place header over content relative to scroll offset + final double maxOffset = size.height - headerHeight; + final headerParentData = + _headerBox.parentData as MultiChildLayoutParentData; + headerParentData.offset = + Offset(0.0, max(0.0, min(-stuckOffset, maxOffset))); + + // report to widget how much the header is stuck. + if (_callback != null) { + final stuckAmount = + max(min(headerHeight, stuckOffset), -headerHeight) / headerHeight; + _callback!(stuckAmount); + } + defaultPaint(context, offset); } } From a3f6cba75471ba16462e5def50794c1c0ce53dfc Mon Sep 17 00:00:00 2001 From: jaap aarts Date: Thu, 26 Jan 2023 13:30:47 +0100 Subject: [PATCH 2/2] Only do layout when needed --- lib/sticky_headers/render.dart | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/sticky_headers/render.dart b/lib/sticky_headers/render.dart index 4b63764..523f067 100644 --- a/lib/sticky_headers/render.dart +++ b/lib/sticky_headers/render.dart @@ -49,10 +49,10 @@ class RenderStickyHeader extends RenderBox } final ScrollPosition oldValue = _scrollPosition; _scrollPosition = newValue; - markNeedsLayout(); + markNeedsPaint(); if (attached) { - oldValue.removeListener(markNeedsLayout); - newValue.addListener(markNeedsLayout); + oldValue.removeListener(markNeedsPaint); + newValue.addListener(markNeedsPaint); } } @@ -61,7 +61,7 @@ class RenderStickyHeader extends RenderBox return; } _callback = newValue; - markNeedsLayout(); + markNeedsPaint(); } set overlapHeaders(bool newValue) { @@ -75,12 +75,12 @@ class RenderStickyHeader extends RenderBox @override void attach(PipelineOwner owner) { super.attach(owner); - _scrollPosition.addListener(markNeedsLayout); + _scrollPosition.addListener(markNeedsPaint); } @override void detach() { - _scrollPosition.removeListener(markNeedsLayout); + _scrollPosition.removeListener(markNeedsPaint); super.detach(); }