mirror of
https://github.com/flutter/flutter.git
synced 2026-01-20 20:55:29 +08:00
WIP Commits separated as follows: - Update lints in analysis_options files - Run `dart fix --apply` - Clean up leftover analysis issues - Run `dart format .` in the right places. Local analysis and testing passes. Checking CI now. Part of https://github.com/flutter/flutter/issues/178827 - Adoption of flutter_lints in examples/api coming in a separate change (cc @loic-sharma) ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
1800 lines
59 KiB
Dart
1800 lines
59 KiB
Dart
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'package:flutter/rendering.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
import 'rendering_tester.dart';
|
|
|
|
void main() {
|
|
TestRenderingFlutterBinding.ensureInitialized();
|
|
|
|
test(
|
|
'RenderViewport calculates correct constraints, RenderSliverToBoxAdapter calculates correct geometry',
|
|
() {
|
|
final children = List<RenderSliver>.generate(30, (int index) {
|
|
return RenderSliverToBoxAdapter(child: RenderSizedBox(const Size(400.0, 100.0)));
|
|
});
|
|
|
|
// Viewport is 800x600, can show 6 children at a time.
|
|
|
|
final root = RenderViewport(
|
|
crossAxisDirection: AxisDirection.right,
|
|
offset: ViewportOffset.zero(),
|
|
cacheExtent: 250.0,
|
|
children: children,
|
|
);
|
|
layout(root);
|
|
|
|
RenderSliver firstVisible = children[0];
|
|
expectSliverConstraints(
|
|
sliver: firstVisible,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 600.0 + 250.0,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: firstVisible,
|
|
paintExtent: 100.0,
|
|
cacheExtent: 100.0,
|
|
visible: true,
|
|
);
|
|
|
|
RenderSliver lastVisible = children[5];
|
|
expectSliverConstraints(
|
|
sliver: lastVisible,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: 100.0,
|
|
remainingCacheExtent: 350.0,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: lastVisible,
|
|
paintExtent: 100.0,
|
|
cacheExtent: 100.0,
|
|
visible: true,
|
|
);
|
|
|
|
RenderSliver firstInCache = children[6];
|
|
expectSliverConstraints(
|
|
sliver: firstInCache,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: 0.0,
|
|
remainingCacheExtent: 250.0,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: firstInCache,
|
|
paintExtent: 0.0,
|
|
cacheExtent: 100.0,
|
|
visible: false,
|
|
);
|
|
|
|
RenderSliver lastInCache = children[8];
|
|
expectSliverConstraints(
|
|
sliver: lastInCache,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: 0.0,
|
|
remainingCacheExtent: 50.0,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: lastInCache,
|
|
paintExtent: 0.0,
|
|
cacheExtent: 50.0,
|
|
visible: false,
|
|
);
|
|
|
|
RenderSliver outsideCache = children[9];
|
|
expectSliverConstraints(
|
|
sliver: outsideCache,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: 0.0,
|
|
remainingCacheExtent: 0.0,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: outsideCache,
|
|
paintExtent: 0.0,
|
|
cacheExtent: 0.0,
|
|
visible: false,
|
|
);
|
|
|
|
// scroll down half a sliver
|
|
root.offset = ViewportOffset.fixed(50.0);
|
|
pumpFrame();
|
|
|
|
firstVisible = children[0];
|
|
expectSliverConstraints(
|
|
sliver: firstVisible,
|
|
cacheOrigin: -50.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 50.0 + 600.0 + 250.0,
|
|
scrollOffset: 50.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: firstVisible,
|
|
paintExtent: 50.0,
|
|
cacheExtent: 100.0,
|
|
visible: true,
|
|
);
|
|
|
|
lastVisible = children[6];
|
|
expectSliverConstraints(
|
|
sliver: lastVisible,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: 50.0,
|
|
remainingCacheExtent: 300.0,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: lastVisible,
|
|
paintExtent: 50.0,
|
|
cacheExtent: 100.0,
|
|
visible: true,
|
|
);
|
|
|
|
firstInCache = children[7];
|
|
expectSliverConstraints(
|
|
sliver: firstInCache,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: 0.0,
|
|
remainingCacheExtent: 200.0,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: firstInCache,
|
|
paintExtent: 0.0,
|
|
cacheExtent: 100.0,
|
|
visible: false,
|
|
);
|
|
|
|
lastInCache = children[8];
|
|
expectSliverConstraints(
|
|
sliver: lastInCache,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: 0.0,
|
|
remainingCacheExtent: 100.0,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: lastInCache,
|
|
paintExtent: 0.0,
|
|
cacheExtent: 100.0,
|
|
visible: false,
|
|
);
|
|
|
|
outsideCache = children[9];
|
|
expectSliverConstraints(
|
|
sliver: outsideCache,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: 0.0,
|
|
remainingCacheExtent: 0.0,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: outsideCache,
|
|
paintExtent: 0.0,
|
|
cacheExtent: 0.0,
|
|
visible: false,
|
|
);
|
|
|
|
// scroll down 1.5 slivers
|
|
root.offset = ViewportOffset.fixed(150.0);
|
|
pumpFrame();
|
|
|
|
RenderSliver firstInPreCache = children[0];
|
|
expectSliverConstraints(
|
|
sliver: firstInPreCache,
|
|
cacheOrigin: -150.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 150.0 + 600.0 + 250.0,
|
|
scrollOffset: 150.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: firstInPreCache,
|
|
paintExtent: 0.0,
|
|
cacheExtent: 100.0,
|
|
visible: false,
|
|
);
|
|
|
|
firstVisible = children[1];
|
|
expectSliverConstraints(
|
|
sliver: firstVisible,
|
|
cacheOrigin: -50.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 50.0 + 600.0 + 250.0,
|
|
scrollOffset: 50.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: firstVisible,
|
|
paintExtent: 50.0,
|
|
cacheExtent: 100.0,
|
|
visible: true,
|
|
);
|
|
|
|
// scroll down 10 slivers
|
|
root.offset = ViewportOffset.fixed(1000.0);
|
|
pumpFrame();
|
|
|
|
final RenderSliver first = children[0];
|
|
expectSliverConstraints(
|
|
sliver: first,
|
|
cacheOrigin: -250.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 250.0 + 600.0 + 250.0,
|
|
scrollOffset: 1000.0,
|
|
);
|
|
expectSliverGeometry(sliver: first, paintExtent: 0.0, cacheExtent: 0.0, visible: false);
|
|
|
|
firstInPreCache = children[7];
|
|
expectSliverConstraints(
|
|
sliver: firstInPreCache,
|
|
cacheOrigin: -250.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 250.0 + 600.0 + 250.0,
|
|
scrollOffset: 300.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: firstInPreCache,
|
|
paintExtent: 0.0,
|
|
cacheExtent: 50.0,
|
|
visible: false,
|
|
);
|
|
|
|
final RenderSliver lastInPreCache = children[9];
|
|
expectSliverConstraints(
|
|
sliver: lastInPreCache,
|
|
cacheOrigin: -100.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 100.0 + 600.0 + 250.0,
|
|
scrollOffset: 100.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: lastInPreCache,
|
|
paintExtent: 0.0,
|
|
cacheExtent: 100.0,
|
|
visible: false,
|
|
);
|
|
|
|
firstVisible = children[10];
|
|
expectSliverConstraints(
|
|
sliver: firstVisible,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 600.0 + 250.0,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: firstVisible,
|
|
paintExtent: 100.0,
|
|
cacheExtent: 100.0,
|
|
visible: true,
|
|
);
|
|
},
|
|
);
|
|
|
|
test('RenderSliverFixedExtentList calculates correct geometry', () {
|
|
// Viewport is 800x600, can show 6 full children at a time
|
|
final children = List<RenderBox>.generate(30, (int index) {
|
|
return RenderSizedBox(const Size(400.0, 100.0));
|
|
});
|
|
final childManager = TestRenderSliverBoxChildManager(children: children);
|
|
RenderSliverFixedExtentList inner;
|
|
final root = RenderViewport(
|
|
crossAxisDirection: AxisDirection.right,
|
|
offset: ViewportOffset.zero(),
|
|
cacheExtent: 250.0,
|
|
children: <RenderSliver>[inner = childManager.createRenderSliverFixedExtentList()],
|
|
);
|
|
layout(root);
|
|
|
|
expectSliverConstraints(
|
|
sliver: inner,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 600.0 + 250.0,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(sliver: inner, paintExtent: 600.0, cacheExtent: 850.0, visible: true);
|
|
expect(children.sublist(0, 9).every((RenderBox r) => r.attached), true);
|
|
expect(children.sublist(9, 30).any((RenderBox r) => r.attached), false);
|
|
|
|
// scroll half an item down
|
|
root.offset = ViewportOffset.fixed(50.0);
|
|
pumpFrame();
|
|
|
|
expectSliverConstraints(
|
|
sliver: inner,
|
|
cacheOrigin: -50.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 50.0 + 600.0 + 250.0,
|
|
scrollOffset: 50.0,
|
|
);
|
|
expectSliverGeometry(sliver: inner, paintExtent: 600.0, cacheExtent: 900.0, visible: true);
|
|
expect(children.sublist(0, 9).every((RenderBox r) => r.attached), true);
|
|
expect(children.sublist(9, 30).any((RenderBox r) => r.attached), false);
|
|
|
|
// scroll to the middle
|
|
root.offset = ViewportOffset.fixed(1500.0);
|
|
pumpFrame();
|
|
|
|
expectSliverConstraints(
|
|
sliver: inner,
|
|
cacheOrigin: -250.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 250.0 + 600.0 + 250.0,
|
|
scrollOffset: 1500.0,
|
|
);
|
|
expectSliverGeometry(sliver: inner, paintExtent: 600.0, cacheExtent: 1100.0, visible: true);
|
|
|
|
expect(children.sublist(0, 12).any((RenderBox r) => r.attached), false);
|
|
expect(children.sublist(12, 24).every((RenderBox r) => r.attached), true);
|
|
expect(children.sublist(24, 30).any((RenderBox r) => r.attached), false);
|
|
|
|
// scroll to the end
|
|
root.offset = ViewportOffset.fixed(2400.0);
|
|
pumpFrame();
|
|
|
|
expectSliverConstraints(
|
|
sliver: inner,
|
|
cacheOrigin: -250.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 250.0 + 600.0 + 250.0,
|
|
scrollOffset: 2400.0,
|
|
);
|
|
expectSliverGeometry(sliver: inner, paintExtent: 600.0, cacheExtent: 850.0, visible: true);
|
|
expect(children.sublist(0, 21).any((RenderBox r) => r.attached), false);
|
|
expect(children.sublist(21, 30).every((RenderBox r) => r.attached), true);
|
|
});
|
|
|
|
test('RenderSliverList calculates correct geometry', () {
|
|
// Viewport is 800x600, can show 6 full children at a time
|
|
final children = List<RenderBox>.generate(30, (int index) {
|
|
return RenderSizedBox(const Size(400.0, 100.0));
|
|
});
|
|
final childManager = TestRenderSliverBoxChildManager(children: children);
|
|
RenderSliverList inner;
|
|
final root = RenderViewport(
|
|
crossAxisDirection: AxisDirection.right,
|
|
offset: ViewportOffset.zero(),
|
|
cacheExtent: 250.0,
|
|
children: <RenderSliver>[inner = childManager.createRenderSliverList()],
|
|
);
|
|
layout(root);
|
|
|
|
expectSliverConstraints(
|
|
sliver: inner,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 600.0 + 250.0,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(sliver: inner, paintExtent: 600.0, cacheExtent: 850.0, visible: true);
|
|
expect(children.sublist(0, 9).every((RenderBox r) => r.attached), true);
|
|
expect(children.sublist(9, 30).any((RenderBox r) => r.attached), false);
|
|
|
|
// scroll half an item down
|
|
root.offset = ViewportOffset.fixed(50.0);
|
|
pumpFrame();
|
|
|
|
expectSliverConstraints(
|
|
sliver: inner,
|
|
cacheOrigin: -50.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 50.0 + 600.0 + 250.0,
|
|
scrollOffset: 50.0,
|
|
);
|
|
expectSliverGeometry(sliver: inner, paintExtent: 600.0, cacheExtent: 900.0, visible: true);
|
|
expect(children.sublist(0, 9).every((RenderBox r) => r.attached), true);
|
|
expect(children.sublist(9, 30).any((RenderBox r) => r.attached), false);
|
|
|
|
// scroll to the middle
|
|
root.offset = ViewportOffset.fixed(1500.0);
|
|
pumpFrame();
|
|
|
|
expectSliverConstraints(
|
|
sliver: inner,
|
|
cacheOrigin: -250.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 250.0 + 600.0 + 250.0,
|
|
scrollOffset: 1500.0,
|
|
);
|
|
expectSliverGeometry(sliver: inner, paintExtent: 600.0, cacheExtent: 1100.0, visible: true);
|
|
|
|
expect(children.sublist(0, 12).any((RenderBox r) => r.attached), false);
|
|
expect(children.sublist(12, 24).every((RenderBox r) => r.attached), true);
|
|
expect(children.sublist(24, 30).any((RenderBox r) => r.attached), false);
|
|
|
|
// scroll to the end
|
|
root.offset = ViewportOffset.fixed(2400.0);
|
|
pumpFrame();
|
|
|
|
expectSliverConstraints(
|
|
sliver: inner,
|
|
cacheOrigin: -250.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 250.0 + 600.0 + 250.0,
|
|
scrollOffset: 2400.0,
|
|
);
|
|
expectSliverGeometry(sliver: inner, paintExtent: 600.0, cacheExtent: 850.0, visible: true);
|
|
expect(children.sublist(0, 21).any((RenderBox r) => r.attached), false);
|
|
expect(children.sublist(21, 30).every((RenderBox r) => r.attached), true);
|
|
});
|
|
|
|
test('RenderSliverGrid calculates correct geometry', () {
|
|
// Viewport is 800x600, each grid element is 400x100, giving us space for 12 visible children
|
|
final children = List<RenderBox>.generate(60, (int index) {
|
|
return RenderSizedBox(const Size(400.0, 100.0));
|
|
});
|
|
final childManager = TestRenderSliverBoxChildManager(children: children);
|
|
RenderSliverGrid inner;
|
|
final root = RenderViewport(
|
|
crossAxisDirection: AxisDirection.right,
|
|
offset: ViewportOffset.zero(),
|
|
cacheExtent: 250.0,
|
|
children: <RenderSliver>[inner = childManager.createRenderSliverGrid()],
|
|
);
|
|
layout(root);
|
|
|
|
expectSliverConstraints(
|
|
sliver: inner,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 600.0 + 250.0,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(sliver: inner, paintExtent: 600.0, cacheExtent: 850.0, visible: true);
|
|
expect(children.sublist(0, 18).every((RenderBox r) => r.attached), true);
|
|
expect(children.sublist(18, 60).any((RenderBox r) => r.attached), false);
|
|
|
|
// scroll half an item down
|
|
root.offset = ViewportOffset.fixed(50.0);
|
|
pumpFrame();
|
|
|
|
expectSliverConstraints(
|
|
sliver: inner,
|
|
cacheOrigin: -50.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 50.0 + 600.0 + 250.0,
|
|
scrollOffset: 50.0,
|
|
);
|
|
expectSliverGeometry(sliver: inner, paintExtent: 600.0, cacheExtent: 900.0, visible: true);
|
|
expect(children.sublist(0, 18).every((RenderBox r) => r.attached), true);
|
|
expect(children.sublist(18, 60).any((RenderBox r) => r.attached), false);
|
|
|
|
// scroll to the middle
|
|
root.offset = ViewportOffset.fixed(1500.0);
|
|
pumpFrame();
|
|
|
|
expectSliverConstraints(
|
|
sliver: inner,
|
|
cacheOrigin: -250.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 250.0 + 600.0 + 250.0,
|
|
scrollOffset: 1500.0,
|
|
);
|
|
expectSliverGeometry(sliver: inner, paintExtent: 600.0, cacheExtent: 1100.0, visible: true);
|
|
|
|
expect(children.sublist(0, 24).any((RenderBox r) => r.attached), false);
|
|
expect(children.sublist(24, 48).every((RenderBox r) => r.attached), true);
|
|
expect(children.sublist(48, 60).any((RenderBox r) => r.attached), false);
|
|
|
|
// scroll to the end
|
|
root.offset = ViewportOffset.fixed(2400.0);
|
|
pumpFrame();
|
|
|
|
expectSliverConstraints(
|
|
sliver: inner,
|
|
cacheOrigin: -250.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 250.0 + 600.0 + 250.0,
|
|
scrollOffset: 2400.0,
|
|
);
|
|
expectSliverGeometry(sliver: inner, paintExtent: 600.0, cacheExtent: 850.0, visible: true);
|
|
expect(children.sublist(0, 42).any((RenderBox r) => r.attached), false);
|
|
expect(children.sublist(42, 60).every((RenderBox r) => r.attached), true);
|
|
});
|
|
|
|
test('RenderSliverPadding calculates correct geometry', () {
|
|
// Viewport is 800x600, each item is 100px high with 50px before and after = 200px
|
|
|
|
final adapters = <RenderSliverToBoxAdapter>[];
|
|
final paddings = List<RenderSliverPadding>.generate(30, (int index) {
|
|
RenderSliverToBoxAdapter adapter;
|
|
final padding = RenderSliverPadding(
|
|
padding: const EdgeInsets.symmetric(vertical: 50.0),
|
|
child: adapter = RenderSliverToBoxAdapter(child: RenderSizedBox(const Size(400.0, 100.0))),
|
|
);
|
|
adapters.add(adapter);
|
|
return padding;
|
|
});
|
|
|
|
final root = RenderViewport(
|
|
crossAxisDirection: AxisDirection.right,
|
|
offset: ViewportOffset.zero(),
|
|
cacheExtent: 250.0,
|
|
children: paddings,
|
|
);
|
|
layout(root);
|
|
|
|
RenderSliverPadding firstVisiblePadding = paddings[0];
|
|
expectSliverConstraints(
|
|
sliver: firstVisiblePadding,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 600.0 + 250.0,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: firstVisiblePadding,
|
|
paintExtent: 200.0,
|
|
cacheExtent: 200.0,
|
|
visible: true,
|
|
);
|
|
RenderSliverToBoxAdapter firstVisiblePadded = adapters[0];
|
|
expectSliverConstraints(
|
|
sliver: firstVisiblePadded,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: 550.0,
|
|
remainingCacheExtent: 600.0 + 250.0 - 50.0,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: firstVisiblePadded,
|
|
paintExtent: 100.0,
|
|
cacheExtent: 100.0,
|
|
visible: true,
|
|
);
|
|
|
|
RenderSliverPadding lastVisiblePadding = paddings[2];
|
|
expectSliverConstraints(
|
|
sliver: lastVisiblePadding,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: 200.0,
|
|
remainingCacheExtent: 200.0 + 250.0,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: lastVisiblePadding,
|
|
paintExtent: 200.0,
|
|
cacheExtent: 200.0,
|
|
visible: true,
|
|
);
|
|
RenderSliverToBoxAdapter lastVisiblePadded = adapters[2];
|
|
expectSliverConstraints(
|
|
sliver: lastVisiblePadded,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: 150.0,
|
|
remainingCacheExtent: 200.0 + 250.0 - 50.0,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: lastVisiblePadded,
|
|
paintExtent: 100.0,
|
|
cacheExtent: 100.0,
|
|
visible: true,
|
|
);
|
|
|
|
final RenderSliverPadding firstCachePadding = paddings[3];
|
|
expectSliverConstraints(
|
|
sliver: firstCachePadding,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: 0.0,
|
|
remainingCacheExtent: 250.0,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: firstCachePadding,
|
|
paintExtent: 0.0,
|
|
cacheExtent: 200.0,
|
|
visible: false,
|
|
);
|
|
final RenderSliverToBoxAdapter firstCachePadded = adapters[3];
|
|
expectSliverConstraints(
|
|
sliver: firstCachePadded,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: 0.0,
|
|
remainingCacheExtent: 250.0 - 50.0,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: firstCachePadded,
|
|
paintExtent: 0.0,
|
|
cacheExtent: 100.0,
|
|
visible: false,
|
|
);
|
|
|
|
final RenderSliverPadding lastCachePadding = paddings[4];
|
|
expectSliverConstraints(
|
|
sliver: lastCachePadding,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: 0.0,
|
|
remainingCacheExtent: 50.0,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: lastCachePadding,
|
|
paintExtent: 0.0,
|
|
cacheExtent: 50.0,
|
|
visible: false,
|
|
);
|
|
final RenderSliverToBoxAdapter lastCachePadded = adapters[4];
|
|
expectSliverConstraints(
|
|
sliver: lastCachePadded,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: 0.0,
|
|
remainingCacheExtent: 0.0,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: lastCachePadded,
|
|
paintExtent: 0.0,
|
|
cacheExtent: 0.0,
|
|
visible: false,
|
|
);
|
|
|
|
// scroll first padding off screen
|
|
root.offset = ViewportOffset.fixed(50.0);
|
|
pumpFrame();
|
|
|
|
firstVisiblePadding = paddings[0];
|
|
expectSliverConstraints(
|
|
sliver: firstVisiblePadding,
|
|
cacheOrigin: -50.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 50.0 + 600.0 + 250.0,
|
|
scrollOffset: 50.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: firstVisiblePadding,
|
|
paintExtent: 150.0,
|
|
cacheExtent: 200.0,
|
|
visible: true,
|
|
);
|
|
firstVisiblePadded = adapters[0];
|
|
expectSliverConstraints(
|
|
sliver: firstVisiblePadded,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 600.0 + 250.0,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: firstVisiblePadded,
|
|
paintExtent: 100.0,
|
|
cacheExtent: 100.0,
|
|
visible: true,
|
|
);
|
|
|
|
// scroll to the end
|
|
root.offset = ViewportOffset.fixed(5400.0);
|
|
pumpFrame();
|
|
|
|
final RenderSliverPadding firstPadding = paddings[0];
|
|
expectSliverConstraints(
|
|
sliver: firstPadding,
|
|
cacheOrigin: -250.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 250.0 + 600.0 + 250.0,
|
|
scrollOffset: 5400.0,
|
|
);
|
|
expectSliverGeometry(sliver: firstPadding, paintExtent: 0.0, cacheExtent: 0.0, visible: false);
|
|
final RenderSliverToBoxAdapter firstPadded = adapters[0];
|
|
expectSliverConstraints(
|
|
sliver: firstPadded,
|
|
cacheOrigin: -200.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 250.0 + 600.0 + 250.0,
|
|
scrollOffset: 5350.0,
|
|
);
|
|
expectSliverGeometry(sliver: firstPadded, paintExtent: 0.0, cacheExtent: 0.0, visible: false);
|
|
|
|
final RenderSliverPadding firstPreCachePadding = paddings[25];
|
|
expectSliverConstraints(
|
|
sliver: firstPreCachePadding,
|
|
cacheOrigin: -250.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 250.0 + 600.0 + 250.0,
|
|
scrollOffset: 400.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: firstPreCachePadding,
|
|
paintExtent: 0.0,
|
|
cacheExtent: 50.0,
|
|
visible: false,
|
|
);
|
|
final RenderSliverToBoxAdapter firstPreCachePadded = adapters[25];
|
|
expectSliverConstraints(
|
|
sliver: firstPreCachePadded,
|
|
cacheOrigin: -200.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 250.0 + 600.0 + 250.0,
|
|
scrollOffset: 350.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: firstPreCachePadded,
|
|
paintExtent: 0.0,
|
|
cacheExtent: 0.0,
|
|
visible: false,
|
|
);
|
|
|
|
final RenderSliverPadding lastPreCachePadding = paddings[26];
|
|
expectSliverConstraints(
|
|
sliver: lastPreCachePadding,
|
|
cacheOrigin: -200.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 200.0 + 600.0 + 250.0,
|
|
scrollOffset: 200.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: lastPreCachePadding,
|
|
paintExtent: 0.0,
|
|
cacheExtent: 200.0,
|
|
visible: false,
|
|
);
|
|
final RenderSliverToBoxAdapter lastPreCachePadded = adapters[26];
|
|
expectSliverConstraints(
|
|
sliver: lastPreCachePadded,
|
|
cacheOrigin: -150.0,
|
|
remainingPaintExtent: 600.0,
|
|
remainingCacheExtent: 150.0 + 600.0 + 250.0,
|
|
scrollOffset: 150.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: lastPreCachePadded,
|
|
paintExtent: 0.0,
|
|
cacheExtent: 100.0,
|
|
visible: false,
|
|
);
|
|
|
|
lastVisiblePadding = paddings[29];
|
|
expectSliverConstraints(
|
|
sliver: lastVisiblePadding,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: 200.0,
|
|
remainingCacheExtent: 200.0 + 250.0,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: lastVisiblePadding,
|
|
paintExtent: 200.0,
|
|
cacheExtent: 200.0,
|
|
visible: true,
|
|
);
|
|
lastVisiblePadded = adapters[29];
|
|
expectSliverConstraints(
|
|
sliver: lastVisiblePadded,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: 150.0,
|
|
remainingCacheExtent: 150.0 + 250.0,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: lastVisiblePadded,
|
|
paintExtent: 100.0,
|
|
cacheExtent: 100.0,
|
|
visible: true,
|
|
);
|
|
});
|
|
|
|
group('RenderSliverFillRemaining calculates correct geometry', () {
|
|
test('when initially in view', () {
|
|
// Viewport is 800x600
|
|
const double viewportHeight = 600;
|
|
const double viewportWidth = 800;
|
|
const cacheExtent = 250.0;
|
|
const double beginningViewportCacheExtent = viewportHeight + cacheExtent;
|
|
const double firstSliverHeight = 400;
|
|
const sliverFillRemainingChildHeight = 100.0;
|
|
|
|
final slivers = <RenderSliver>[
|
|
RenderSliverToBoxAdapter(child: RenderSizedBox(const Size(400.0, firstSliverHeight))),
|
|
RenderSliverFillRemaining(
|
|
child: RenderSizedBox(const Size(100.0, sliverFillRemainingChildHeight)),
|
|
),
|
|
];
|
|
|
|
final root = RenderViewport(
|
|
crossAxisDirection: AxisDirection.right,
|
|
offset: ViewportOffset.zero(),
|
|
cacheExtent: cacheExtent,
|
|
children: slivers,
|
|
);
|
|
layout(root);
|
|
|
|
final RenderSliver firstVisibleSliver = slivers[0];
|
|
expectSliverConstraints(
|
|
sliver: firstVisibleSliver,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: viewportHeight,
|
|
remainingCacheExtent: beginningViewportCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: firstVisibleSliver,
|
|
paintExtent: firstSliverHeight,
|
|
cacheExtent: firstSliverHeight,
|
|
visible: true,
|
|
);
|
|
|
|
// With RenderSliverFillRemaining:
|
|
// * The child has a minExtent and maxExtent of the remaining space of the
|
|
// viewportMainAxisExtent or the height of the child - whichever is larger.
|
|
// * The sliver has a paintExtent of the child's minExtent/maxExtent or the
|
|
// remainingPaintExtent - whichever is smaller.
|
|
// * The sliver has a cacheExtent of the child's minExtent/maxExtent or the
|
|
// remainingCacheExtent - whichever is smaller.
|
|
final sliverFillRemaining = slivers[1] as RenderSliverSingleBoxAdapter;
|
|
const double extentOfChild = viewportHeight - firstSliverHeight;
|
|
double remainingPaintExtent = viewportHeight - firstSliverHeight;
|
|
double remainingCacheExtent = beginningViewportCacheExtent - firstSliverHeight;
|
|
expectSliverConstraints(
|
|
sliver: sliverFillRemaining,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: remainingPaintExtent,
|
|
remainingCacheExtent: remainingCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverChildConstraints(
|
|
sliver: sliverFillRemaining,
|
|
maxHeight: extentOfChild,
|
|
minHeight: extentOfChild,
|
|
maxWidth: viewportWidth,
|
|
minWidth: viewportWidth,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: sliverFillRemaining,
|
|
paintExtent: extentOfChild,
|
|
cacheExtent: extentOfChild,
|
|
visible: true,
|
|
);
|
|
|
|
// Overscroll
|
|
const double scrollOffset = 50;
|
|
root.offset = ViewportOffset.fixed(scrollOffset);
|
|
pumpFrame();
|
|
remainingPaintExtent = viewportHeight - firstSliverHeight + scrollOffset;
|
|
remainingCacheExtent = beginningViewportCacheExtent - firstSliverHeight + scrollOffset;
|
|
|
|
// With RenderSliverFillRemaining, when you overscroll, the extent of the
|
|
// child does not change and therefore neither does paintExtent or cacheExtent.
|
|
expectSliverConstraints(
|
|
sliver: sliverFillRemaining,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: remainingPaintExtent,
|
|
remainingCacheExtent: remainingCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverChildConstraints(
|
|
sliver: sliverFillRemaining,
|
|
maxHeight: extentOfChild,
|
|
minHeight: extentOfChild,
|
|
maxWidth: viewportWidth,
|
|
minWidth: viewportWidth,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: sliverFillRemaining,
|
|
paintExtent: extentOfChild,
|
|
cacheExtent: extentOfChild,
|
|
visible: true,
|
|
);
|
|
});
|
|
|
|
test('when scrolled into view', () {
|
|
// Viewport is 800x600
|
|
const double viewportHeight = 600;
|
|
const double viewportWidth = 800;
|
|
const cacheExtent = 250.0;
|
|
const double beginningViewportCacheExtent = viewportHeight + cacheExtent;
|
|
const firstSliverHeight = beginningViewportCacheExtent;
|
|
const sliverFillRemainingChildHeight = 100.0;
|
|
|
|
final slivers = <RenderSliver>[
|
|
RenderSliverToBoxAdapter(child: RenderSizedBox(const Size(400.0, firstSliverHeight))),
|
|
RenderSliverFillRemaining(
|
|
child: RenderSizedBox(const Size(100.0, sliverFillRemainingChildHeight)),
|
|
),
|
|
];
|
|
|
|
final root = RenderViewport(
|
|
crossAxisDirection: AxisDirection.right,
|
|
offset: ViewportOffset.zero(),
|
|
cacheExtent: cacheExtent,
|
|
children: slivers,
|
|
);
|
|
layout(root);
|
|
|
|
final RenderSliver firstVisibleSliver = slivers[0];
|
|
expectSliverConstraints(
|
|
sliver: firstVisibleSliver,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: viewportHeight,
|
|
remainingCacheExtent: beginningViewportCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: firstVisibleSliver,
|
|
paintExtent: viewportHeight,
|
|
cacheExtent: firstSliverHeight,
|
|
visible: true,
|
|
);
|
|
|
|
// With RenderSliverFillRemaining:
|
|
// * The child has a minExtent and maxExtent of the remaining space of the
|
|
// viewportMainAxisExtent or the height of the child - whichever is larger.
|
|
// * The sliver has a paintExtent of the child's minExtent/maxExtent or the
|
|
// remainingPaintExtent - whichever is smaller.
|
|
// * The sliver has a cacheExtent of the child's minExtent/maxExtent or the
|
|
// remainingCacheExtent - whichever is smaller.
|
|
final sliverFillRemaining = slivers[1] as RenderSliverSingleBoxAdapter;
|
|
const extentOfChild = sliverFillRemainingChildHeight;
|
|
double remainingPaintExtent = 0;
|
|
double remainingCacheExtent = 0;
|
|
expectSliverConstraints(
|
|
sliver: sliverFillRemaining,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: remainingPaintExtent,
|
|
remainingCacheExtent: remainingCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverChildConstraints(
|
|
sliver: sliverFillRemaining,
|
|
maxHeight: extentOfChild,
|
|
minHeight: extentOfChild,
|
|
maxWidth: viewportWidth,
|
|
minWidth: viewportWidth,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: sliverFillRemaining,
|
|
paintExtent: remainingPaintExtent,
|
|
cacheExtent: remainingCacheExtent,
|
|
visible: false,
|
|
);
|
|
|
|
// Scroll so RenderSliverFillRemaining is not within viewport, but is
|
|
// within remainingCacheExtent.
|
|
root.offset = ViewportOffset.fixed(cacheExtent);
|
|
pumpFrame();
|
|
remainingPaintExtent = 0;
|
|
remainingCacheExtent = cacheExtent;
|
|
|
|
// When within the remainingCacheExtent, the sliver will have a cacheExtent
|
|
// of the child's extent.
|
|
expectSliverConstraints(
|
|
sliver: sliverFillRemaining,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: remainingPaintExtent,
|
|
remainingCacheExtent: remainingCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverChildConstraints(
|
|
sliver: sliverFillRemaining,
|
|
maxHeight: extentOfChild,
|
|
minHeight: extentOfChild,
|
|
maxWidth: viewportWidth,
|
|
minWidth: viewportWidth,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: sliverFillRemaining,
|
|
paintExtent: remainingPaintExtent,
|
|
cacheExtent: extentOfChild,
|
|
visible: false,
|
|
);
|
|
|
|
// Scroll so RenderSliverFillRemaining is partially within viewport.
|
|
root.offset = ViewportOffset.fixed(cacheExtent + 50);
|
|
pumpFrame();
|
|
remainingPaintExtent = 50;
|
|
remainingCacheExtent = cacheExtent + 50;
|
|
|
|
expectSliverConstraints(
|
|
sliver: sliverFillRemaining,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: remainingPaintExtent,
|
|
remainingCacheExtent: remainingCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverChildConstraints(
|
|
sliver: sliverFillRemaining,
|
|
maxHeight: extentOfChild,
|
|
minHeight: extentOfChild,
|
|
maxWidth: viewportWidth,
|
|
minWidth: viewportWidth,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: sliverFillRemaining,
|
|
paintExtent: remainingPaintExtent,
|
|
cacheExtent: extentOfChild,
|
|
visible: true,
|
|
);
|
|
|
|
// Scroll so RenderSliverFillRemaining is completely within viewport.
|
|
root.offset = ViewportOffset.fixed(cacheExtent + sliverFillRemainingChildHeight);
|
|
pumpFrame();
|
|
remainingPaintExtent = sliverFillRemainingChildHeight;
|
|
remainingCacheExtent = cacheExtent + sliverFillRemainingChildHeight;
|
|
|
|
expectSliverConstraints(
|
|
sliver: sliverFillRemaining,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: remainingPaintExtent,
|
|
remainingCacheExtent: remainingCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverChildConstraints(
|
|
sliver: sliverFillRemaining,
|
|
maxHeight: extentOfChild,
|
|
minHeight: extentOfChild,
|
|
maxWidth: viewportWidth,
|
|
minWidth: viewportWidth,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: sliverFillRemaining,
|
|
paintExtent: extentOfChild,
|
|
cacheExtent: extentOfChild,
|
|
visible: true,
|
|
);
|
|
|
|
// Overscroll
|
|
root.offset = ViewportOffset.fixed(cacheExtent + sliverFillRemainingChildHeight + 50);
|
|
pumpFrame();
|
|
remainingPaintExtent = sliverFillRemainingChildHeight + 50;
|
|
remainingCacheExtent = cacheExtent + sliverFillRemainingChildHeight + 50;
|
|
|
|
// With RenderSliverFillRemaining, when you overscroll, the extent of the
|
|
// child does not change and therefore neither does paintExtent or cacheExtent.
|
|
expectSliverConstraints(
|
|
sliver: sliverFillRemaining,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: remainingPaintExtent,
|
|
remainingCacheExtent: remainingCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverChildConstraints(
|
|
sliver: sliverFillRemaining,
|
|
maxHeight: extentOfChild,
|
|
minHeight: extentOfChild,
|
|
maxWidth: viewportWidth,
|
|
minWidth: viewportWidth,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: sliverFillRemaining,
|
|
paintExtent: extentOfChild,
|
|
cacheExtent: extentOfChild,
|
|
visible: true,
|
|
);
|
|
});
|
|
});
|
|
|
|
group('RenderSliverFillRemainingAndOverscroll calculates correct geometry', () {
|
|
test('when initially in view', () {
|
|
// Viewport is 800x600
|
|
const double viewportHeight = 600;
|
|
const double viewportWidth = 800;
|
|
const cacheExtent = 250.0;
|
|
const double beginningViewportCacheExtent = viewportHeight + cacheExtent;
|
|
const double firstSliverHeight = 400;
|
|
const sliverFillRemainingChildHeight = 100.0;
|
|
|
|
final slivers = <RenderSliver>[
|
|
RenderSliverToBoxAdapter(child: RenderSizedBox(const Size(400.0, firstSliverHeight))),
|
|
RenderSliverFillRemainingAndOverscroll(
|
|
child: RenderSizedBox(const Size(100.0, sliverFillRemainingChildHeight)),
|
|
),
|
|
];
|
|
|
|
final root = RenderViewport(
|
|
crossAxisDirection: AxisDirection.right,
|
|
offset: ViewportOffset.zero(),
|
|
cacheExtent: cacheExtent,
|
|
children: slivers,
|
|
);
|
|
layout(root);
|
|
|
|
final RenderSliver firstVisibleSliver = slivers[0];
|
|
expectSliverConstraints(
|
|
sliver: firstVisibleSliver,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: viewportHeight,
|
|
remainingCacheExtent: beginningViewportCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: firstVisibleSliver,
|
|
paintExtent: firstSliverHeight,
|
|
cacheExtent: firstSliverHeight,
|
|
visible: true,
|
|
);
|
|
|
|
// With RenderSliverFillRemainingAndOverscroll:
|
|
// * The child has a minExtent of the remaining space of the viewportMainAxisExtent
|
|
// or the height of the child - whichever is larger.
|
|
// * The child has a maxExtent of the remaining space of the viewportMainAxisExtent,
|
|
// the height of the child, or the remainingPaintExtent - whichever is larger.
|
|
// * The sliver has a paintExtent of the child's maxExtent or the
|
|
// remainingPaintExtent - whichever is smaller.
|
|
// * The sliver has a cacheExtent of the child's minExtent or the
|
|
// remainingCacheExtent - whichever is smaller.
|
|
final sliverFillRemaining = slivers[1] as RenderSliverSingleBoxAdapter;
|
|
const double minExtentOfChild = viewportHeight - firstSliverHeight;
|
|
double maxExtentOfChild = viewportHeight - firstSliverHeight;
|
|
double remainingPaintExtent = viewportHeight - firstSliverHeight;
|
|
double remainingCacheExtent = beginningViewportCacheExtent - firstSliverHeight;
|
|
expectSliverConstraints(
|
|
sliver: sliverFillRemaining,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: remainingPaintExtent,
|
|
remainingCacheExtent: remainingCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverChildConstraints(
|
|
sliver: sliverFillRemaining,
|
|
maxHeight: maxExtentOfChild,
|
|
minHeight: minExtentOfChild,
|
|
maxWidth: viewportWidth,
|
|
minWidth: viewportWidth,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: sliverFillRemaining,
|
|
paintExtent: maxExtentOfChild,
|
|
cacheExtent: minExtentOfChild,
|
|
visible: true,
|
|
);
|
|
|
|
// Overscroll
|
|
const double scrollOffset = 50;
|
|
root.offset = ViewportOffset.fixed(scrollOffset);
|
|
pumpFrame();
|
|
remainingPaintExtent = viewportHeight - firstSliverHeight + scrollOffset;
|
|
remainingCacheExtent = beginningViewportCacheExtent - firstSliverHeight + scrollOffset;
|
|
|
|
// When you overscroll, the child's maxExtent is the
|
|
// remainingPaintExtent, since it's the higher value.
|
|
maxExtentOfChild = remainingPaintExtent;
|
|
expectSliverConstraints(
|
|
sliver: sliverFillRemaining,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: remainingPaintExtent,
|
|
remainingCacheExtent: remainingCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverChildConstraints(
|
|
sliver: sliverFillRemaining,
|
|
maxHeight: maxExtentOfChild,
|
|
minHeight: minExtentOfChild,
|
|
maxWidth: viewportWidth,
|
|
minWidth: viewportWidth,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: sliverFillRemaining,
|
|
paintExtent: maxExtentOfChild,
|
|
cacheExtent: minExtentOfChild,
|
|
visible: true,
|
|
);
|
|
});
|
|
|
|
test('when scrolled into view', () {
|
|
// Viewport is 800x600
|
|
const double viewportHeight = 600;
|
|
const double viewportWidth = 800;
|
|
const cacheExtent = 250.0;
|
|
const double beginningViewportCacheExtent = viewportHeight + cacheExtent;
|
|
const firstSliverHeight = beginningViewportCacheExtent;
|
|
const sliverFillRemainingChildHeight = 100.0;
|
|
|
|
final slivers = <RenderSliver>[
|
|
RenderSliverToBoxAdapter(child: RenderSizedBox(const Size(400.0, firstSliverHeight))),
|
|
RenderSliverFillRemainingAndOverscroll(
|
|
child: RenderSizedBox(const Size(100.0, sliverFillRemainingChildHeight)),
|
|
),
|
|
];
|
|
|
|
final root = RenderViewport(
|
|
crossAxisDirection: AxisDirection.right,
|
|
offset: ViewportOffset.zero(),
|
|
cacheExtent: cacheExtent,
|
|
children: slivers,
|
|
);
|
|
layout(root);
|
|
|
|
final RenderSliver firstVisibleSliver = slivers[0];
|
|
expectSliverConstraints(
|
|
sliver: firstVisibleSliver,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: viewportHeight,
|
|
remainingCacheExtent: beginningViewportCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: firstVisibleSliver,
|
|
paintExtent: viewportHeight,
|
|
cacheExtent: firstSliverHeight,
|
|
visible: true,
|
|
);
|
|
|
|
// With RenderSliverFillRemainingAndOverscroll:
|
|
// * The child has a minExtent of the remaining space of the viewportMainAxisExtent
|
|
// or the height of the child - whichever is larger.
|
|
// * The child has a maxExtent of the remaining space of the viewportMainAxisExtent,
|
|
// the height of the child, or the remainingPaintExtent - whichever is larger.
|
|
// * The sliver has a paintExtent of the child's maxExtent or the
|
|
// remainingPaintExtent - whichever is smaller.
|
|
// * The sliver has a cacheExtent of the child's minExtent or the
|
|
// remainingCacheExtent - whichever is smaller.
|
|
final sliverFillRemaining = slivers[1] as RenderSliverSingleBoxAdapter;
|
|
const minExtentOfChild = sliverFillRemainingChildHeight;
|
|
var maxExtentOfChild = sliverFillRemainingChildHeight;
|
|
double remainingPaintExtent = 0;
|
|
double remainingCacheExtent = 0;
|
|
expectSliverConstraints(
|
|
sliver: sliverFillRemaining,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: remainingPaintExtent,
|
|
remainingCacheExtent: remainingCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverChildConstraints(
|
|
sliver: sliverFillRemaining,
|
|
maxHeight: maxExtentOfChild,
|
|
minHeight: minExtentOfChild,
|
|
maxWidth: viewportWidth,
|
|
minWidth: viewportWidth,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: sliverFillRemaining,
|
|
paintExtent: remainingPaintExtent,
|
|
cacheExtent: remainingCacheExtent,
|
|
visible: false,
|
|
);
|
|
|
|
// Scroll so RenderSliverFillRemainingAndOverscroll is not within viewport,
|
|
// but is within remainingCacheExtent.
|
|
root.offset = ViewportOffset.fixed(cacheExtent);
|
|
pumpFrame();
|
|
remainingPaintExtent = 0;
|
|
remainingCacheExtent = cacheExtent;
|
|
|
|
// When within the remainingCacheExtent, the sliver will have a cacheExtent
|
|
// of the child's minExtent.
|
|
expectSliverConstraints(
|
|
sliver: sliverFillRemaining,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: remainingPaintExtent,
|
|
remainingCacheExtent: remainingCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverChildConstraints(
|
|
sliver: sliverFillRemaining,
|
|
maxHeight: maxExtentOfChild,
|
|
minHeight: minExtentOfChild,
|
|
maxWidth: viewportWidth,
|
|
minWidth: viewportWidth,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: sliverFillRemaining,
|
|
paintExtent: remainingPaintExtent,
|
|
cacheExtent: minExtentOfChild,
|
|
visible: false,
|
|
);
|
|
|
|
// Scroll so RenderSliverFillRemainingAndOverscroll is partially within
|
|
// the viewport.
|
|
root.offset = ViewportOffset.fixed(cacheExtent + 50);
|
|
pumpFrame();
|
|
remainingPaintExtent = 50;
|
|
remainingCacheExtent = cacheExtent + 50;
|
|
|
|
expectSliverConstraints(
|
|
sliver: sliverFillRemaining,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: remainingPaintExtent,
|
|
remainingCacheExtent: remainingCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverChildConstraints(
|
|
sliver: sliverFillRemaining,
|
|
maxHeight: maxExtentOfChild,
|
|
minHeight: minExtentOfChild,
|
|
maxWidth: viewportWidth,
|
|
minWidth: viewportWidth,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: sliverFillRemaining,
|
|
paintExtent: remainingPaintExtent,
|
|
cacheExtent: minExtentOfChild,
|
|
visible: true,
|
|
);
|
|
|
|
// Scroll so RenderSliverFillRemainingAndOverscroll is completely within
|
|
// the viewport.
|
|
root.offset = ViewportOffset.fixed(cacheExtent + sliverFillRemainingChildHeight);
|
|
pumpFrame();
|
|
remainingPaintExtent = sliverFillRemainingChildHeight;
|
|
remainingCacheExtent = cacheExtent + sliverFillRemainingChildHeight;
|
|
|
|
// When completely in view, the slivers's paintExtent is the child's
|
|
// maxExtentOfChild, since it's the smaller value.
|
|
expectSliverConstraints(
|
|
sliver: sliverFillRemaining,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: remainingPaintExtent,
|
|
remainingCacheExtent: remainingCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverChildConstraints(
|
|
sliver: sliverFillRemaining,
|
|
maxHeight: maxExtentOfChild,
|
|
minHeight: minExtentOfChild,
|
|
maxWidth: viewportWidth,
|
|
minWidth: viewportWidth,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: sliverFillRemaining,
|
|
paintExtent: maxExtentOfChild,
|
|
cacheExtent: minExtentOfChild,
|
|
visible: true,
|
|
);
|
|
|
|
// Overscroll
|
|
root.offset = ViewportOffset.fixed(cacheExtent + sliverFillRemainingChildHeight + 50);
|
|
pumpFrame();
|
|
remainingPaintExtent = sliverFillRemainingChildHeight + 50;
|
|
remainingCacheExtent = cacheExtent + sliverFillRemainingChildHeight + 50;
|
|
|
|
// When you overscroll, the child's maxExtent is the remainingPaintExtent,
|
|
// since it's the higher value.
|
|
maxExtentOfChild = remainingPaintExtent;
|
|
expectSliverConstraints(
|
|
sliver: sliverFillRemaining,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: remainingPaintExtent,
|
|
remainingCacheExtent: remainingCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverChildConstraints(
|
|
sliver: sliverFillRemaining,
|
|
maxHeight: maxExtentOfChild,
|
|
minHeight: minExtentOfChild,
|
|
maxWidth: viewportWidth,
|
|
minWidth: viewportWidth,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: sliverFillRemaining,
|
|
paintExtent: maxExtentOfChild,
|
|
cacheExtent: minExtentOfChild,
|
|
visible: true,
|
|
);
|
|
});
|
|
});
|
|
|
|
group('RenderSliverFillRemainingWithScrollable calculates correct geometry', () {
|
|
test('when initially in view', () {
|
|
// Viewport is 800x600
|
|
const double viewportHeight = 600;
|
|
const double viewportWidth = 800;
|
|
const cacheExtent = 250.0;
|
|
const double beginningViewportCacheExtent = viewportHeight + cacheExtent;
|
|
const double firstSliverHeight = 400;
|
|
const sliverFillRemainingChildHeight = 100.0;
|
|
|
|
final slivers = <RenderSliver>[
|
|
RenderSliverToBoxAdapter(child: RenderSizedBox(const Size(400.0, firstSliverHeight))),
|
|
RenderSliverFillRemainingWithScrollable(
|
|
child: RenderSizedBox(const Size(100.0, sliverFillRemainingChildHeight)),
|
|
),
|
|
];
|
|
|
|
final root = RenderViewport(
|
|
crossAxisDirection: AxisDirection.right,
|
|
offset: ViewportOffset.zero(),
|
|
cacheExtent: cacheExtent,
|
|
children: slivers,
|
|
);
|
|
layout(root);
|
|
|
|
final RenderSliver firstVisibleSliver = slivers[0];
|
|
expectSliverConstraints(
|
|
sliver: firstVisibleSliver,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: viewportHeight,
|
|
remainingCacheExtent: beginningViewportCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: firstVisibleSliver,
|
|
paintExtent: firstSliverHeight,
|
|
cacheExtent: firstSliverHeight,
|
|
visible: true,
|
|
);
|
|
|
|
// With RenderSliverFillRemainingWithScrollable:
|
|
// * The child has a minExtent of the remainingPaintExtent.
|
|
// * If not within the viewport but within the cacheExtent, the child has
|
|
// a maxExtent of the sliver's cacheExtent. Otherwise, the child has a
|
|
// maxExtent of the remainingPaintExtent
|
|
// * The sliver has a paintExtent of the child's minExtent or the
|
|
// remainingPaintExtent - whichever is smaller.
|
|
// * The sliver has a cacheExtent of either the viewportMainAxisExtent or
|
|
// the remainingCacheExtent - whichever is smaller.
|
|
final sliverFillRemaining = slivers[1] as RenderSliverSingleBoxAdapter;
|
|
double remainingPaintExtent = viewportHeight - firstSliverHeight;
|
|
double remainingCacheExtent = beginningViewportCacheExtent - firstSliverHeight;
|
|
var minExtentOfChild = remainingPaintExtent;
|
|
var maxExtentOfChild = remainingPaintExtent;
|
|
|
|
expectSliverConstraints(
|
|
sliver: sliverFillRemaining,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: remainingPaintExtent,
|
|
remainingCacheExtent: remainingCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverChildConstraints(
|
|
sliver: sliverFillRemaining,
|
|
maxHeight: maxExtentOfChild,
|
|
minHeight: minExtentOfChild,
|
|
maxWidth: viewportWidth,
|
|
minWidth: viewportWidth,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: sliverFillRemaining,
|
|
paintExtent: minExtentOfChild,
|
|
cacheExtent: remainingCacheExtent,
|
|
visible: true,
|
|
);
|
|
|
|
// Overscroll so first sliver is partially out of view.
|
|
root.offset = ViewportOffset.fixed(50);
|
|
pumpFrame();
|
|
remainingPaintExtent = viewportHeight - firstSliverHeight + 50;
|
|
remainingCacheExtent = beginningViewportCacheExtent - firstSliverHeight + 50;
|
|
minExtentOfChild = remainingPaintExtent;
|
|
maxExtentOfChild = remainingPaintExtent;
|
|
|
|
expectSliverConstraints(
|
|
sliver: sliverFillRemaining,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: remainingPaintExtent,
|
|
remainingCacheExtent: remainingCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverChildConstraints(
|
|
sliver: sliverFillRemaining,
|
|
maxHeight: maxExtentOfChild,
|
|
minHeight: minExtentOfChild,
|
|
maxWidth: viewportWidth,
|
|
minWidth: viewportWidth,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: sliverFillRemaining,
|
|
paintExtent: minExtentOfChild,
|
|
cacheExtent: remainingCacheExtent,
|
|
visible: true,
|
|
);
|
|
|
|
// Overscroll so only RenderSliverFillRemainingWithScrollable is visible.
|
|
root.offset = ViewportOffset.fixed(firstSliverHeight);
|
|
pumpFrame();
|
|
remainingPaintExtent = viewportHeight;
|
|
remainingCacheExtent = beginningViewportCacheExtent;
|
|
minExtentOfChild = remainingPaintExtent;
|
|
maxExtentOfChild = remainingPaintExtent;
|
|
|
|
expectSliverConstraints(
|
|
sliver: sliverFillRemaining,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: remainingPaintExtent,
|
|
remainingCacheExtent: remainingCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverChildConstraints(
|
|
sliver: sliverFillRemaining,
|
|
maxHeight: maxExtentOfChild,
|
|
minHeight: minExtentOfChild,
|
|
maxWidth: viewportWidth,
|
|
minWidth: viewportWidth,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: sliverFillRemaining,
|
|
paintExtent: minExtentOfChild,
|
|
cacheExtent: viewportHeight,
|
|
visible: true,
|
|
);
|
|
});
|
|
|
|
test('when scrolled into view', () {
|
|
// Viewport is 800x600
|
|
const double viewportHeight = 600;
|
|
const double viewportWidth = 800;
|
|
const cacheExtent = 250.0;
|
|
const double beginningViewportCacheExtent = viewportHeight + cacheExtent;
|
|
const firstSliverHeight = beginningViewportCacheExtent;
|
|
const sliverFillRemainingChildHeight = 100.0;
|
|
|
|
final slivers = <RenderSliver>[
|
|
RenderSliverToBoxAdapter(child: RenderSizedBox(const Size(400.0, firstSliverHeight))),
|
|
RenderSliverFillRemainingWithScrollable(
|
|
child: RenderSizedBox(const Size(100.0, sliverFillRemainingChildHeight)),
|
|
),
|
|
];
|
|
|
|
final root = RenderViewport(
|
|
crossAxisDirection: AxisDirection.right,
|
|
offset: ViewportOffset.zero(),
|
|
cacheExtent: cacheExtent,
|
|
children: slivers,
|
|
);
|
|
layout(root);
|
|
|
|
final RenderSliver firstVisibleSliver = slivers[0];
|
|
expectSliverConstraints(
|
|
sliver: firstVisibleSliver,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: viewportHeight,
|
|
remainingCacheExtent: beginningViewportCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: firstVisibleSliver,
|
|
paintExtent: viewportHeight,
|
|
cacheExtent: firstSliverHeight,
|
|
visible: true,
|
|
);
|
|
|
|
// With RenderSliverFillRemainingWithScrollable:
|
|
// * The child has a minExtent of the remainingPaintExtent.
|
|
// * If not within the viewport but within the cacheExtent, the child has
|
|
// a maxExtent of the sliver's cacheExtent. Otherwise, the child has a
|
|
// maxExtent of the remainingPaintExtent
|
|
// * The sliver has a paintExtent of the child's minExtent or the
|
|
// remainingPaintExtent - whichever is smaller.
|
|
// * The sliver has a cacheExtent of either the viewportMainAxisExtent or
|
|
// the remainingCacheExtent - whichever is smaller.
|
|
final sliverFillRemaining = slivers[1] as RenderSliverSingleBoxAdapter;
|
|
double remainingPaintExtent = 0;
|
|
double remainingCacheExtent = 0;
|
|
var minExtentOfChild = remainingPaintExtent;
|
|
var maxExtentOfChild = remainingPaintExtent;
|
|
expectSliverConstraints(
|
|
sliver: sliverFillRemaining,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: remainingPaintExtent,
|
|
remainingCacheExtent: remainingCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverChildConstraints(
|
|
sliver: sliverFillRemaining,
|
|
maxHeight: maxExtentOfChild,
|
|
minHeight: minExtentOfChild,
|
|
maxWidth: viewportWidth,
|
|
minWidth: viewportWidth,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: sliverFillRemaining,
|
|
paintExtent: minExtentOfChild,
|
|
cacheExtent: remainingCacheExtent,
|
|
visible: false,
|
|
);
|
|
|
|
// Scroll so RenderSliverFillRemainingWithScrollable is not within
|
|
// viewport, but is within remainingCacheExtent.
|
|
root.offset = ViewportOffset.fixed(cacheExtent);
|
|
pumpFrame();
|
|
remainingPaintExtent = 0;
|
|
remainingCacheExtent = cacheExtent;
|
|
minExtentOfChild = remainingPaintExtent;
|
|
// When RenderSliverFillRemainingWithScrollable is completely outside the
|
|
// viewport, but is within the remainingCacheExtent, the child has a
|
|
// maxExtent of the slivers's cacheExtent.
|
|
maxExtentOfChild = remainingCacheExtent;
|
|
|
|
expectSliverConstraints(
|
|
sliver: sliverFillRemaining,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: remainingPaintExtent,
|
|
remainingCacheExtent: remainingCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverChildConstraints(
|
|
sliver: sliverFillRemaining,
|
|
maxHeight: maxExtentOfChild,
|
|
minHeight: minExtentOfChild,
|
|
maxWidth: viewportWidth,
|
|
minWidth: viewportWidth,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: sliverFillRemaining,
|
|
paintExtent: minExtentOfChild,
|
|
cacheExtent: remainingCacheExtent,
|
|
visible: false,
|
|
);
|
|
|
|
// Scroll so RenderSliverFillRemainingWithScrollable is partially within
|
|
// viewport.
|
|
root.offset = ViewportOffset.fixed(cacheExtent + 50);
|
|
pumpFrame();
|
|
remainingPaintExtent = 50;
|
|
remainingCacheExtent = cacheExtent + 50;
|
|
minExtentOfChild = remainingPaintExtent;
|
|
maxExtentOfChild = remainingPaintExtent;
|
|
|
|
expectSliverConstraints(
|
|
sliver: sliverFillRemaining,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: remainingPaintExtent,
|
|
remainingCacheExtent: remainingCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverChildConstraints(
|
|
sliver: sliverFillRemaining,
|
|
maxHeight: maxExtentOfChild,
|
|
minHeight: minExtentOfChild,
|
|
maxWidth: viewportWidth,
|
|
minWidth: viewportWidth,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: sliverFillRemaining,
|
|
paintExtent: minExtentOfChild,
|
|
cacheExtent: remainingCacheExtent,
|
|
visible: true,
|
|
);
|
|
|
|
// Scroll so RenderSliverFillRemainingWithScrollable takes the entire
|
|
// viewport.
|
|
root.offset = ViewportOffset.fixed(firstSliverHeight);
|
|
pumpFrame();
|
|
remainingPaintExtent = viewportHeight;
|
|
remainingCacheExtent = beginningViewportCacheExtent;
|
|
minExtentOfChild = remainingPaintExtent;
|
|
maxExtentOfChild = remainingPaintExtent;
|
|
|
|
expectSliverConstraints(
|
|
sliver: sliverFillRemaining,
|
|
cacheOrigin: 0.0,
|
|
remainingPaintExtent: remainingPaintExtent,
|
|
remainingCacheExtent: remainingCacheExtent,
|
|
scrollOffset: 0.0,
|
|
);
|
|
expectSliverChildConstraints(
|
|
sliver: sliverFillRemaining,
|
|
maxHeight: maxExtentOfChild,
|
|
minHeight: minExtentOfChild,
|
|
maxWidth: viewportWidth,
|
|
minWidth: viewportWidth,
|
|
);
|
|
expectSliverGeometry(
|
|
sliver: sliverFillRemaining,
|
|
paintExtent: minExtentOfChild,
|
|
cacheExtent: viewportHeight,
|
|
visible: true,
|
|
);
|
|
});
|
|
});
|
|
}
|
|
|
|
void expectSliverConstraints({
|
|
required RenderSliver sliver,
|
|
required double cacheOrigin,
|
|
required double remainingPaintExtent,
|
|
required double remainingCacheExtent,
|
|
required double scrollOffset,
|
|
}) {
|
|
expect(sliver.constraints.cacheOrigin, cacheOrigin, reason: 'cacheOrigin');
|
|
expect(
|
|
sliver.constraints.remainingPaintExtent,
|
|
remainingPaintExtent,
|
|
reason: 'remainingPaintExtent',
|
|
);
|
|
expect(
|
|
sliver.constraints.remainingCacheExtent,
|
|
remainingCacheExtent,
|
|
reason: 'remainingCacheExtent',
|
|
);
|
|
expect(sliver.constraints.scrollOffset, scrollOffset, reason: 'scrollOffset');
|
|
}
|
|
|
|
void expectSliverGeometry({
|
|
required RenderSliver sliver,
|
|
required double paintExtent,
|
|
required double cacheExtent,
|
|
required bool visible,
|
|
}) {
|
|
expect(sliver.geometry!.paintExtent, paintExtent, reason: 'paintExtent');
|
|
expect(sliver.geometry!.cacheExtent, cacheExtent, reason: 'cacheExtent');
|
|
expect(sliver.geometry!.visible, visible, reason: 'visible');
|
|
}
|
|
|
|
void expectSliverChildConstraints({
|
|
required RenderSliverSingleBoxAdapter sliver,
|
|
required double maxWidth,
|
|
required double maxHeight,
|
|
required double minWidth,
|
|
required double minHeight,
|
|
}) {
|
|
expect(sliver.child!.constraints.maxWidth, maxWidth, reason: 'maxWidth');
|
|
expect(sliver.child!.constraints.maxHeight, maxHeight, reason: 'maxHeight');
|
|
expect(sliver.child!.constraints.minWidth, minWidth, reason: 'minWidth');
|
|
expect(sliver.child!.constraints.minHeight, minHeight, reason: 'minHeight');
|
|
}
|
|
|
|
class TestRenderSliverBoxChildManager extends RenderSliverBoxChildManager {
|
|
TestRenderSliverBoxChildManager({required this.children});
|
|
|
|
RenderSliverMultiBoxAdaptor? _renderObject;
|
|
List<RenderBox> children;
|
|
|
|
RenderSliverList createRenderSliverList() {
|
|
assert(_renderObject == null);
|
|
_renderObject = RenderSliverList(childManager: this);
|
|
return _renderObject! as RenderSliverList;
|
|
}
|
|
|
|
RenderSliverFixedExtentList createRenderSliverFixedExtentList() {
|
|
assert(_renderObject == null);
|
|
_renderObject = RenderSliverFixedExtentList(childManager: this, itemExtent: 100.0);
|
|
return _renderObject! as RenderSliverFixedExtentList;
|
|
}
|
|
|
|
RenderSliverGrid createRenderSliverGrid() {
|
|
assert(_renderObject == null);
|
|
_renderObject = RenderSliverGrid(
|
|
childManager: this,
|
|
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
|
crossAxisCount: 2,
|
|
childAspectRatio: 4.0,
|
|
),
|
|
);
|
|
return _renderObject! as RenderSliverGrid;
|
|
}
|
|
|
|
int? _currentlyUpdatingChildIndex;
|
|
|
|
@override
|
|
void createChild(int index, {required RenderBox? after}) {
|
|
if (index < 0 || index >= children.length) {
|
|
return;
|
|
}
|
|
try {
|
|
_currentlyUpdatingChildIndex = index;
|
|
_renderObject!.insert(children[index], after: after);
|
|
} finally {
|
|
_currentlyUpdatingChildIndex = null;
|
|
}
|
|
}
|
|
|
|
@override
|
|
void removeChild(RenderBox child) {
|
|
_renderObject!.remove(child);
|
|
}
|
|
|
|
@override
|
|
double estimateMaxScrollOffset(
|
|
SliverConstraints constraints, {
|
|
int? firstIndex,
|
|
int? lastIndex,
|
|
double? leadingScrollOffset,
|
|
double? trailingScrollOffset,
|
|
}) {
|
|
assert(lastIndex! >= firstIndex!);
|
|
return children.length *
|
|
(trailingScrollOffset! - leadingScrollOffset!) /
|
|
(lastIndex! - firstIndex! + 1);
|
|
}
|
|
|
|
@override
|
|
int get childCount => children.length;
|
|
|
|
@override
|
|
void didAdoptChild(RenderBox child) {
|
|
assert(_currentlyUpdatingChildIndex != null);
|
|
final childParentData = child.parentData! as SliverMultiBoxAdaptorParentData;
|
|
childParentData.index = _currentlyUpdatingChildIndex;
|
|
}
|
|
|
|
@override
|
|
void setDidUnderflow(bool value) {}
|
|
}
|