Skip to content

Commit

Permalink
Multi sliver box children (#26)
Browse files Browse the repository at this point in the history
* First part of accepting box children in multisliver

* Made box children work

* Made boxchild hittesting work correctly

* Fixed box children interfering with other hit testing

* Updated version and changelog

* Fixed minor analysis warnings

* Minor QA fixes

* Updated version
  • Loading branch information
Kavantix committed Mar 30, 2021
1 parent 84f35aa commit 16c783e
Show file tree
Hide file tree
Showing 8 changed files with 418 additions and 123 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# 0.2.1

- Fixed floating point rounding error that happens in debug mode
This version essentially makes the `SliverToBoxAdapter` widget obsolete.
MultiSliver now accepts `RenderBox` children directly!🎉

- Accept box children of MultiSliver.
- Fixed floating point rounding error that happens in debug mode.

# 0.2.0

Expand Down
292 changes: 192 additions & 100 deletions lib/src/rendering/multi_sliver.dart

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lib/src/sliver_animated_paint_extent.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ class _SliverAnimatedPaintExtentState extends State<SliverAnimatedPaintExtent>
return _SliverAnimatedPaintExtent(
controller: _controller,
duration: widget.duration,
child: widget.child,
curve: widget.curve,
child: widget.child,
);
}
}
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: sliver_tools
description: A set of useful sliver tools that are missing from the flutter framework
version: 0.2.0
version: 0.2.1
homepage: https://github.com/Kavantix
repository: https://github.com/Kavantix/sliver_tools
issue_tracker: https://github.com/Kavantix/sliver_tools/issues
Expand Down
225 changes: 212 additions & 13 deletions test/multi_sliver_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ import 'helpers/unconstrained_scroll_physics.dart';

void main() => multiSliverTests();

Widget box(Key? key, String title, {required double height}) {
return Container(
key: key,
alignment: Alignment.center,
height: height,
width: double.infinity,
child: Text(title),
);
}

void multiSliverTests() {
group('MultiSliver', () {
Widget box(Key? key, String title, {required double height}) {
return Container(
key: key,
alignment: Alignment.center,
height: height,
width: double.infinity,
child: Text(title),
);
}

const box1Key = ValueKey('1');
const box2Key = ValueKey('2');
const groupKey = ValueKey('group');
Expand Down Expand Up @@ -50,9 +50,7 @@ void multiSliverTests() {
size: pinnedSize,
boxKey: pinnedKey,
),
SliverToBoxAdapter(
child: box(box1Key, '1', height: 150),
),
box(box1Key, '1', height: 150),
SliverList(
key: listKey,
delegate: SliverChildBuilderDelegate(
Expand Down Expand Up @@ -210,5 +208,206 @@ void multiSliverTests() {
await tester.pump();
expect(tester.takeException(), isNull);
});

testWidgets('accepts RenderBox children', (tester) async {
const boxKey = Key('box');
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
child: CustomScrollView(
slivers: [
MultiSliver(
children: [
box(boxKey, 'Title', height: 200),
],
),
],
),
));
expect(find.byKey(boxKey), findsOneWidget);
expect(find.text('Title'), findsOneWidget);
});

testWidgets('correctly draws boxChild when scrolled off screen',
(tester) async {
const boxKey = Key('box');
final controller = ScrollController();
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
child: CustomScrollView(
controller: controller,
physics: const UnconstrainedScollPhysics(),
slivers: [
MultiSliver(
children: [
box(boxKey, 'Title', height: 200),
],
),
],
),
));
expect(find.byKey(boxKey), findsOneWidget);
expect(find.text('Title'), findsOneWidget);
Rect boxRect() => tester.getRect(find.byKey(boxKey));
final boxWidth = boxRect().width;
expect(boxRect(), Rect.fromLTWH(0, 0, boxWidth, 200));
controller.jumpTo(100);
await tester.pump();
expect(boxRect(), Rect.fromLTWH(0, -100, boxWidth, 200));
controller.jumpTo(199);
await tester.pump();
expect(boxRect(), Rect.fromLTWH(0, -199, boxWidth, 200));
controller.jumpTo(300);
await tester.pump();
expect(find.byKey(boxKey), findsNothing);
});

testWidgets(
'correctly sets hasVisualOverflow of boxChild when scrolled off screen',
(tester) async {
const boxKey = Key('box');
final controller = ScrollController();
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
child: CustomScrollView(
controller: controller,
physics: const UnconstrainedScollPhysics(),
slivers: [
MultiSliver(
children: [
box(boxKey, 'Title', height: 200),
],
),
],
),
));
expect(find.byKey(boxKey), findsOneWidget);
expect(find.text('Title'), findsOneWidget);
final boxRenderObject = tester.renderObject(find.byKey(boxKey));
Rect boxRect() => tester.getRect(find.byKey(boxKey));
SliverGeometry boxGeometry() =>
(boxRenderObject.parentData as MultiSliverParentData).geometry;
final boxWidth = boxRect().width;
expect(boxRect(), Rect.fromLTWH(0, 0, boxWidth, 200));
expect(boxGeometry().hasVisualOverflow, false);
controller.jumpTo(100);
await tester.pump();
expect(boxRect(), Rect.fromLTWH(0, -100, boxWidth, 200));
expect(boxGeometry().hasVisualOverflow, true);
controller.jumpTo(199);
await tester.pump();
expect(boxRect(), Rect.fromLTWH(0, -199, boxWidth, 200));
expect(boxGeometry().hasVisualOverflow, true);
controller.jumpTo(300);
await tester.pump();
expect(find.byKey(boxKey), findsNothing);
expect(boxGeometry().hasVisualOverflow, false);
});

testWidgets('can hit sliver child', (tester) async {
const boxKey = Key('box');
final controller = ScrollController();
var taps = 0;
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
child: CustomScrollView(
controller: controller,
physics: const UnconstrainedScollPhysics(),
slivers: [
MultiSliver(
children: [
box(UniqueKey(), 'Title', height: 100),
SliverList(
delegate: SliverChildListDelegate(
[
const SizedBox(height: 100),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => taps++,
child: const SizedBox(
key: boxKey,
height: 1,
),
),
],
),
),
],
),
],
),
));
expect(taps, 0);
final thebox = find.byKey(boxKey);
await tester.tap(thebox);
expect(taps, 1);
controller.jumpTo(100);
await tester.pump();
await tester.tap(thebox);
expect(taps, 2);
});

testWidgets('can hit box child', (tester) async {
const boxKey = Key('box');
final controller = ScrollController();
var taps = 0;
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
child: CustomScrollView(
controller: controller,
physics: const UnconstrainedScollPhysics(),
slivers: [
MultiSliver(
children: [
const SliverToBoxAdapter(child: SizedBox(height: 400)),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => taps++,
child: box(boxKey, 'Title', height: 1),
),
],
),
],
),
));
expect(taps, 0);
final thebox = find.byKey(boxKey);
await tester.tap(thebox);
expect(taps, 1);
});

testWidgets('box child does not get hit when tapping outside',
(tester) async {
const boxKey = Key('box');
final controller = ScrollController();
var taps = 0;
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
child: CustomScrollView(
controller: controller,
physics: const UnconstrainedScollPhysics(),
slivers: [
MultiSliver(
children: [
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => taps++,
child: box(UniqueKey(), 'Title', height: 200),
),
const SliverToBoxAdapter(
child: SizedBox(
key: boxKey,
height: 1,
),
),
],
),
],
),
));
expect(taps, 0);
final thebox = find.byKey(boxKey);
await tester.tap(thebox);
expect(taps, 0);
});
});
}
4 changes: 2 additions & 2 deletions test/sliver_cross_axis_constrained_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ void crossAxisConstrainedTests() {
await tester.pumpWidget(sut);
await tester.pumpAndSettle();

final width = await tester
final width = tester
.renderObject(find.byType(SliverToBoxAdapter))
.paintBounds
.width;
Expand All @@ -65,7 +65,7 @@ void crossAxisConstrainedTests() {
await tester.pumpAndSettle();

final renderObject =
await tester.renderObject(find.byType(SliverToBoxAdapter));
tester.renderObject(find.byType(SliverToBoxAdapter));

expect(renderObject.paintBounds.width, maxCrossAxisExtent);
});
Expand Down
2 changes: 1 addition & 1 deletion test/sliver_cross_axis_padded_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ void crossAxisPaddedTests() {
TextDirection textDirection = TextDirection.ltr,
}) {
return SliverCrossAxisPadded(
child: const SizedBox.shrink(),
textDirection: textDirection,
paddingStart: paddingStart,
paddingEnd: paddingEnd,
child: const SizedBox.shrink(),
);
}

Expand Down
8 changes: 4 additions & 4 deletions test/sliver_stack_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -324,15 +324,15 @@ void sliverStackTests() {
ignoreOverlap: ignoreOverlap,
topPositionedBuilder: (child) => SliverPositioned(
key: key,
left: left,
top: top,
right: right,
bottom: bottom,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => tapped++,
child: child,
),
left: left,
top: top,
right: right,
bottom: bottom,
),
);
final renderStack =
Expand Down

0 comments on commit 16c783e

Please sign in to comment.