Skip to content

Instantly share code, notes, and snippets.

@Piinks
Created April 15, 2026 16:41
Show Gist options
  • Select an option

  • Save Piinks/032622bfabf27c81944b565cfe639ae3 to your computer and use it in GitHub Desktop.

Select an option

Save Piinks/032622bfabf27c81944b565cfe639ae3 to your computer and use it in GitHub Desktop.
Test case for overlap
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('SliverClipRect updates clip when overlap changes even if geometry is same', (WidgetTester tester) async {
final ScrollController controller = ScrollController();
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: CustomScrollView(
controller: controller,
slivers: <Widget>[
const SliverPersistentHeader(
delegate: MyDelegate(maxExtent: 100, minExtent: 100),
pinned: true,
),
const SliverToBoxAdapter(child: SizedBox(height: 100)), // Spacer
SliverClipRect(
sliver: SliverToBoxAdapter(
child: Container(
height: 100,
color: const Color(0xFF2196F3),
),
),
),
const SliverToBoxAdapter(
child: SizedBox(height: 1000),
),
],
),
),
);
final RenderSliverClipRect renderSliver = tester.renderObject(find.byType(SliverClipRect));
// Initial state: no overlap
// Header 0..100, Spacer 100..200, ClipRect 200..300.
expect(renderSliver.constraints.overlap, 0.0);
expect(renderSliver.getClip()!.top, 0.0);
// Scroll by 150.
// Spacer is scrolled off. ClipRect starts at y=50.
// Since Header is pinned at 0..100, it overlaps ClipRect by 50px.
controller.jumpTo(150);
await tester.pump();
expect(renderSliver.constraints.overlap, 50.0);
// This should fail if the bug exists because the ClipRect is still fully visible (paintExtent=100),
// so its geometry didn't change, and _clip was not nulled.
expect(renderSliver.getClip()!.top, 50.0);
});
}
class MyDelegate extends SliverPersistentHeaderDelegate {
const MyDelegate({required this.maxExtent, required this.minExtent});
@override
final double maxExtent;
@override
final double minExtent;
@override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) => SizedBox(height: maxExtent);
@override
bool shouldRebuild(MyDelegate oldDelegate) => maxExtent != oldDelegate.maxExtent || minExtent != oldDelegate.minExtent;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment