SliverBlock->SliverList (#7872)
This commit is contained in:
@@ -46,7 +46,7 @@ export 'src/rendering/semantics.dart';
|
||||
export 'src/rendering/shifted_box.dart';
|
||||
export 'src/rendering/sliver.dart';
|
||||
export 'src/rendering/sliver_app_bar.dart';
|
||||
export 'src/rendering/sliver_block.dart';
|
||||
export 'src/rendering/sliver_fixed_extent_list.dart';
|
||||
export 'src/rendering/sliver_grid.dart';
|
||||
export 'src/rendering/sliver_list.dart';
|
||||
export 'src/rendering/sliver_multi_box_adaptor.dart';
|
||||
@@ -55,8 +55,8 @@ export 'src/rendering/stack.dart';
|
||||
export 'src/rendering/table.dart';
|
||||
export 'src/rendering/tweens.dart';
|
||||
export 'src/rendering/view.dart';
|
||||
export 'src/rendering/viewport_offset.dart';
|
||||
export 'src/rendering/viewport.dart';
|
||||
export 'src/rendering/viewport_offset.dart';
|
||||
|
||||
export 'package:flutter/foundation.dart' show
|
||||
VoidCallback,
|
||||
|
||||
@@ -71,7 +71,8 @@ class Dialog extends StatelessWidget {
|
||||
///
|
||||
/// If the content is too large to fit on the screen vertically, the dialog will
|
||||
/// display the title and the actions and let the content overflow. Consider
|
||||
/// using a scrolling widget, such as [Block], for [content] to avoid overflow.
|
||||
/// using a scrolling widget, such as [ScrollList], for [content] to avoid
|
||||
/// overflow.
|
||||
///
|
||||
/// For dialogs that offer the user a choice between several options, consider
|
||||
/// using a [SimpleDialog].
|
||||
@@ -113,9 +114,9 @@ class AlertDialog extends StatelessWidget {
|
||||
/// The (optional) content of the dialog is displayed in the center of the
|
||||
/// dialog in a lighter font.
|
||||
///
|
||||
/// Typically, this is a [Block] containing the contents of the dialog. Using
|
||||
/// a [Block] ensures that the contents can scroll if they are too big to fit
|
||||
/// on the display.
|
||||
/// Typically, this is a [ScrollList] containing the contents of the dialog.
|
||||
/// Using a [ScrollList] ensures that the contents can scroll if they are too
|
||||
/// big to fit on the display.
|
||||
final Widget content;
|
||||
|
||||
/// Padding around the content.
|
||||
@@ -263,8 +264,8 @@ class SimpleDialog extends StatelessWidget {
|
||||
/// padding will be provided.
|
||||
final EdgeInsets titlePadding;
|
||||
|
||||
/// The (optional) content of the dialog is displayed in a [Block] underneath
|
||||
/// the title.
|
||||
/// The (optional) content of the dialog is displayed in a
|
||||
/// [SingleChildScrollView] underneath the title.
|
||||
///
|
||||
/// Typically a list of [SimpleDialogOption]s.
|
||||
final List<Widget> children;
|
||||
@@ -305,7 +306,7 @@ class SimpleDialog extends StatelessWidget {
|
||||
child: new Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: body
|
||||
children: body,
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -31,7 +31,7 @@ const Duration _kBaseSettleDuration = const Duration(milliseconds: 246);
|
||||
/// the side of the screen and displays a list of items that the user can
|
||||
/// interact with.
|
||||
///
|
||||
/// Typically, the child of the drawer is a [Block] whose first child is a
|
||||
/// Typically, the child of the drawer is a [SliverList] whose first child is a
|
||||
/// [DrawerHeader] that displays status information about the current user.
|
||||
///
|
||||
/// The [Scaffold] automatically shows an appropriate [IconButton], and handles
|
||||
@@ -67,7 +67,7 @@ class Drawer extends StatelessWidget {
|
||||
|
||||
/// The widget below this widget in the tree.
|
||||
///
|
||||
/// Typically a [Block].
|
||||
/// Typically a [SliverList].
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
|
||||
@@ -48,8 +48,8 @@ Map<MaterialListType, double> kListItemExtent = const <MaterialListType, double>
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Block], which shows heterogeneous widgets in a list and makes the list
|
||||
/// scrollable if necessary.
|
||||
/// * [SliverList], which shows heterogeneous widgets in a list and makes the
|
||||
/// list scrollable if necessary.
|
||||
/// * [ListItem], to show content in a [MaterialList] using material design
|
||||
/// conventions.
|
||||
/// * [ScrollableList], on which this widget is based.
|
||||
|
||||
@@ -347,10 +347,8 @@ class Scaffold extends StatefulWidget {
|
||||
///
|
||||
/// If you have a column of widgets that should normally fit on the screen,
|
||||
/// but may overflow and would in such cases need to scroll, consider using a
|
||||
/// [Block] as the body of the scaffold.
|
||||
///
|
||||
/// If you have a list of items, consider using a [LazyBlock],
|
||||
/// [LazyScrollableList], or [MaterialList] as the body of the scaffold.
|
||||
/// [ScrollList] as the body of the scaffold. This is also a good choice for
|
||||
/// the case where your body is a scrollable list.
|
||||
final Widget body;
|
||||
|
||||
/// A button displayed floating above [body], in the bottom right corner.
|
||||
|
||||
@@ -1,215 +0,0 @@
|
||||
// Copyright 2017 The Chromium 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/foundation.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import 'box.dart';
|
||||
import 'sliver.dart';
|
||||
import 'sliver_multi_box_adaptor.dart';
|
||||
|
||||
class RenderSliverBlock extends RenderSliverMultiBoxAdaptor {
|
||||
RenderSliverBlock({
|
||||
@required RenderSliverBoxChildManager childManager
|
||||
}) : super(childManager: childManager);
|
||||
|
||||
@override
|
||||
void performLayout() {
|
||||
assert(childManager.debugAssertChildListLocked());
|
||||
double scrollOffset = constraints.scrollOffset;
|
||||
assert(scrollOffset >= 0.0);
|
||||
double remainingPaintExtent = constraints.remainingPaintExtent;
|
||||
assert(remainingPaintExtent >= 0.0);
|
||||
double targetEndScrollOffset = scrollOffset + remainingPaintExtent;
|
||||
BoxConstraints childConstraints = constraints.asBoxConstraints();
|
||||
int leadingGarbage = 0;
|
||||
int trailingGarbage = 0;
|
||||
bool reachedEnd = false;
|
||||
|
||||
// This algorithm in principle is straight-forward: find the first child
|
||||
// that overlaps the given scrollOffset, creating more children at the top
|
||||
// of the list if necessary, then walk down the list updating and laying out
|
||||
// each child and adding more at the end if necessary until we have enough
|
||||
// children to cover the entire viewport.
|
||||
//
|
||||
// It is complicated by one minor issue, which is that any time you update
|
||||
// or create a child, it's possible that the some of the children that
|
||||
// haven't yet been laid out will be removed, leaving the list in an
|
||||
// inconsistent state, and requiring that missing nodes be recreated.
|
||||
//
|
||||
// To keep this mess tractable, this algorithm starts from what is currently
|
||||
// the first child, if any, and then walks up and/or down from there, so
|
||||
// that the nodes that might get removed are always at the edges of what has
|
||||
// already been laid out.
|
||||
|
||||
// Make sure we have at least one child to start from.
|
||||
if (firstChild == null) {
|
||||
if (!addInitialChild()) {
|
||||
// There are no children.
|
||||
geometry = SliverGeometry.zero;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We have at least one child.
|
||||
|
||||
// These variables track the range of children that we have laid out. Within
|
||||
// this range, the children have consecutive indices. Outside this range,
|
||||
// it's possible for a child to get removed without notice.
|
||||
RenderBox leadingChildWithLayout, trailingChildWithLayout;
|
||||
|
||||
// Find the last child that is at or before the scrollOffset.
|
||||
RenderBox earliestUsefulChild = firstChild;
|
||||
for (double earliestScrollOffset = childScrollOffset(earliestUsefulChild);
|
||||
earliestScrollOffset > scrollOffset;
|
||||
earliestScrollOffset = childScrollOffset(earliestUsefulChild)) {
|
||||
// We have to add children before the earliestUsefulChild.
|
||||
earliestUsefulChild = insertAndLayoutLeadingChild(childConstraints, parentUsesSize: true);
|
||||
if (earliestUsefulChild == null) {
|
||||
// We ran out of children before reaching the scroll offset.
|
||||
// We must inform our parent that this sliver cannot fulfill
|
||||
// its contract and that we need a scroll offset correction.
|
||||
geometry = new SliverGeometry(
|
||||
scrollOffsetCorrection: -childScrollOffset(firstChild),
|
||||
);
|
||||
return;
|
||||
}
|
||||
final SliverMultiBoxAdaptorParentData childParentData = earliestUsefulChild.parentData;
|
||||
childParentData.scrollOffset = earliestScrollOffset - paintExtentOf(firstChild);
|
||||
assert(earliestUsefulChild == firstChild);
|
||||
leadingChildWithLayout = earliestUsefulChild;
|
||||
trailingChildWithLayout ??= earliestUsefulChild;
|
||||
}
|
||||
|
||||
// At this point, earliestUsefulChild is the first child, and is a child
|
||||
// whose scrollOffset is at or before the scrollOffset, and
|
||||
// leadingChildWithLayout and trailingChildWithLayout are either null or
|
||||
// cover a range of render boxes that we have laid out with the first being
|
||||
// the same as earliestUsefulChild and the last being either at or after the
|
||||
// scroll offset.
|
||||
|
||||
assert(earliestUsefulChild == firstChild);
|
||||
assert(childScrollOffset(earliestUsefulChild) <= scrollOffset);
|
||||
|
||||
// Make sure we've laid out at least one child.
|
||||
if (leadingChildWithLayout == null) {
|
||||
earliestUsefulChild.layout(childConstraints, parentUsesSize: true);
|
||||
leadingChildWithLayout = earliestUsefulChild;
|
||||
trailingChildWithLayout = earliestUsefulChild;
|
||||
}
|
||||
|
||||
// Here, earliestUsefulChild is still the first child, it's got a
|
||||
// scrollOffset that is at or before our actual scrollOffset, and it has
|
||||
// been laid out, and is in fact our leadingChildWithLayout. It's possible
|
||||
// that some children beyond that one have also been laid out.
|
||||
|
||||
bool inLayoutRange = true;
|
||||
RenderBox child = earliestUsefulChild;
|
||||
int index = indexOf(child);
|
||||
double endScrollOffset = childScrollOffset(child) + paintExtentOf(child);
|
||||
bool advance() { // returns true if we advanced, false if we have no more children
|
||||
// This function is used in two different places below, to avoid code duplication.
|
||||
assert(child != null);
|
||||
if (child == trailingChildWithLayout)
|
||||
inLayoutRange = false;
|
||||
child = childAfter(child);
|
||||
if (child == null)
|
||||
inLayoutRange = false;
|
||||
index += 1;
|
||||
if (!inLayoutRange) {
|
||||
if (child == null || indexOf(child) != index) {
|
||||
// We are missing a child. Insert it (and lay it out) if possible.
|
||||
child = insertAndLayoutChild(childConstraints,
|
||||
after: trailingChildWithLayout,
|
||||
parentUsesSize: true,
|
||||
);
|
||||
if (child == null) {
|
||||
// We have run out of children.
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Lay out the child.
|
||||
child.layout(childConstraints, parentUsesSize: true);
|
||||
}
|
||||
trailingChildWithLayout = child;
|
||||
}
|
||||
assert(child != null);
|
||||
final SliverMultiBoxAdaptorParentData childParentData = child.parentData;
|
||||
childParentData.scrollOffset = endScrollOffset;
|
||||
assert(childParentData.index == index);
|
||||
endScrollOffset = childScrollOffset(child) + paintExtentOf(child);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Find the first child that ends after the scroll offset.
|
||||
while (endScrollOffset < scrollOffset) {
|
||||
leadingGarbage += 1;
|
||||
if (!advance()) {
|
||||
assert(leadingGarbage == childCount);
|
||||
assert(child == null);
|
||||
// we want to make sure we keep the last child around so we know the end scroll offset
|
||||
collectGarbage(leadingGarbage - 1, 0);
|
||||
assert(firstChild == lastChild);
|
||||
final double extent = childScrollOffset(lastChild) + paintExtentOf(lastChild);
|
||||
geometry = new SliverGeometry(
|
||||
scrollExtent: extent,
|
||||
paintExtent: 0.0,
|
||||
maxPaintExtent: extent,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Now find the first child that ends after our end.
|
||||
while (endScrollOffset < targetEndScrollOffset) {
|
||||
if (!advance()) {
|
||||
reachedEnd = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally count up all the remaining children and label them as garbage.
|
||||
if (child != null) {
|
||||
child = childAfter(child);
|
||||
while (child != null) {
|
||||
trailingGarbage += 1;
|
||||
child = childAfter(child);
|
||||
}
|
||||
}
|
||||
|
||||
// At this point everything should be good to go, we just have to clean up
|
||||
// the garbage and report the geometry.
|
||||
|
||||
collectGarbage(leadingGarbage, trailingGarbage);
|
||||
|
||||
assert(debugAssertChildListIsNonEmptyAndContiguous());
|
||||
double estimatedMaxScrollOffset;
|
||||
if (reachedEnd) {
|
||||
estimatedMaxScrollOffset = endScrollOffset;
|
||||
} else {
|
||||
estimatedMaxScrollOffset = childManager.estimateMaxScrollOffset(
|
||||
constraints,
|
||||
firstIndex: indexOf(firstChild),
|
||||
lastIndex: indexOf(lastChild),
|
||||
leadingScrollOffset: childScrollOffset(firstChild),
|
||||
trailingScrollOffset: endScrollOffset,
|
||||
);
|
||||
assert(estimatedMaxScrollOffset >= endScrollOffset - childScrollOffset(firstChild));
|
||||
}
|
||||
final double paintedExtent = calculatePaintOffset(
|
||||
constraints,
|
||||
from: childScrollOffset(firstChild),
|
||||
to: endScrollOffset,
|
||||
);
|
||||
geometry = new SliverGeometry(
|
||||
scrollExtent: estimatedMaxScrollOffset,
|
||||
paintExtent: paintedExtent,
|
||||
maxPaintExtent: estimatedMaxScrollOffset,
|
||||
// Conservative to avoid flickering away the clip during scroll.
|
||||
hasVisualOverflow: endScrollOffset > targetEndScrollOffset || constraints.scrollOffset > 0.0,
|
||||
);
|
||||
|
||||
assert(childManager.debugAssertChildListLocked());
|
||||
}
|
||||
}
|
||||
152
packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart
Normal file
152
packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart
Normal file
@@ -0,0 +1,152 @@
|
||||
// Copyright 2017 The Chromium 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 'dart:math' as math;
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import 'box.dart';
|
||||
import 'sliver.dart';
|
||||
import 'sliver_multi_box_adaptor.dart';
|
||||
|
||||
abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAdaptor {
|
||||
RenderSliverFixedExtentBoxAdaptor({
|
||||
@required RenderSliverBoxChildManager childManager,
|
||||
}) : super(childManager: childManager);
|
||||
|
||||
/// The main-axis extent of each item.
|
||||
double get itemExtent;
|
||||
|
||||
@override
|
||||
void performLayout() {
|
||||
assert(childManager.debugAssertChildListLocked());
|
||||
|
||||
final double itemExtent = this.itemExtent;
|
||||
double indexToScrollOffset(int index) => itemExtent * index;
|
||||
|
||||
final double scrollOffset = constraints.scrollOffset;
|
||||
assert(scrollOffset >= 0.0);
|
||||
final double remainingPaintExtent = constraints.remainingPaintExtent;
|
||||
assert(remainingPaintExtent >= 0.0);
|
||||
final double targetEndScrollOffset = scrollOffset + remainingPaintExtent;
|
||||
|
||||
BoxConstraints childConstraints = constraints.asBoxConstraints(
|
||||
minExtent: itemExtent,
|
||||
maxExtent: itemExtent,
|
||||
);
|
||||
|
||||
final int firstIndex = math.max(0, scrollOffset ~/ itemExtent);
|
||||
final int targetLastIndex = math.max(0, (targetEndScrollOffset / itemExtent).ceil() - 1);
|
||||
|
||||
if (firstChild != null) {
|
||||
final int oldFirstIndex = indexOf(firstChild);
|
||||
final int oldLastIndex = indexOf(lastChild);
|
||||
final int leadingGarbage = (firstIndex - oldFirstIndex).clamp(0, childCount);
|
||||
final int trailingGarbage = (oldLastIndex - targetLastIndex).clamp(0, childCount);
|
||||
if (leadingGarbage + trailingGarbage > 0)
|
||||
collectGarbage(leadingGarbage, trailingGarbage);
|
||||
}
|
||||
|
||||
if (firstChild == null) {
|
||||
if (!addInitialChild(index: firstIndex, scrollOffset: indexToScrollOffset(firstIndex))) {
|
||||
// There are no children.
|
||||
geometry = SliverGeometry.zero;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
RenderBox trailingChildWithLayout;
|
||||
|
||||
for (int index = indexOf(firstChild) - 1; index >= firstIndex; --index) {
|
||||
final RenderBox child = insertAndLayoutLeadingChild(childConstraints);
|
||||
final SliverMultiBoxAdaptorParentData childParentData = child.parentData;
|
||||
childParentData.scrollOffset = indexToScrollOffset(index);
|
||||
assert(childParentData.index == index);
|
||||
trailingChildWithLayout ??= child;
|
||||
}
|
||||
|
||||
assert(childScrollOffset(firstChild) <= scrollOffset);
|
||||
|
||||
if (trailingChildWithLayout == null) {
|
||||
firstChild.layout(childConstraints);
|
||||
trailingChildWithLayout = firstChild;
|
||||
}
|
||||
|
||||
while (indexOf(trailingChildWithLayout) < targetLastIndex) {
|
||||
RenderBox child = childAfter(trailingChildWithLayout);
|
||||
if (child == null) {
|
||||
child = insertAndLayoutChild(childConstraints, after: trailingChildWithLayout);
|
||||
if (child == null) {
|
||||
// We have run out of children.
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
child.layout(childConstraints);
|
||||
}
|
||||
trailingChildWithLayout = child;
|
||||
assert(child != null);
|
||||
final SliverMultiBoxAdaptorParentData childParentData = child.parentData;
|
||||
childParentData.scrollOffset = indexToScrollOffset(childParentData.index);
|
||||
}
|
||||
|
||||
final int lastIndex = indexOf(lastChild);
|
||||
final double leadingScrollOffset = indexToScrollOffset(firstIndex);
|
||||
final double trailingScrollOffset = indexToScrollOffset(lastIndex + 1);
|
||||
|
||||
assert(debugAssertChildListIsNonEmptyAndContiguous());
|
||||
assert(indexOf(firstChild) == firstIndex);
|
||||
assert(lastIndex <= targetLastIndex);
|
||||
|
||||
final double estimatedMaxScrollOffset = childManager.estimateMaxScrollOffset(
|
||||
constraints,
|
||||
firstIndex: firstIndex,
|
||||
lastIndex: lastIndex,
|
||||
leadingScrollOffset: leadingScrollOffset,
|
||||
trailingScrollOffset: trailingScrollOffset,
|
||||
);
|
||||
|
||||
final double paintedExtent = calculatePaintOffset(
|
||||
constraints,
|
||||
from: leadingScrollOffset,
|
||||
to: trailingScrollOffset,
|
||||
);
|
||||
|
||||
geometry = new SliverGeometry(
|
||||
scrollExtent: estimatedMaxScrollOffset,
|
||||
paintExtent: paintedExtent,
|
||||
maxPaintExtent: estimatedMaxScrollOffset,
|
||||
// Conservative to avoid flickering away the clip during scroll.
|
||||
hasVisualOverflow: lastIndex >= targetLastIndex || constraints.scrollOffset > 0.0,
|
||||
);
|
||||
|
||||
assert(childManager.debugAssertChildListLocked());
|
||||
}
|
||||
}
|
||||
|
||||
class RenderSliverFixedExtentList extends RenderSliverFixedExtentBoxAdaptor {
|
||||
RenderSliverFixedExtentList({
|
||||
@required RenderSliverBoxChildManager childManager,
|
||||
double itemExtent,
|
||||
}) : _itemExtent = itemExtent, super(childManager: childManager);
|
||||
|
||||
@override
|
||||
double get itemExtent => _itemExtent;
|
||||
double _itemExtent;
|
||||
set itemExtent (double newValue) {
|
||||
assert(newValue != null);
|
||||
if (_itemExtent == newValue)
|
||||
return;
|
||||
_itemExtent = newValue;
|
||||
markNeedsLayout();
|
||||
}
|
||||
}
|
||||
|
||||
class RenderSliverFill extends RenderSliverFixedExtentBoxAdaptor {
|
||||
RenderSliverFill({
|
||||
@required RenderSliverBoxChildManager childManager,
|
||||
}) : super(childManager: childManager);
|
||||
|
||||
@override
|
||||
double get itemExtent => constraints.viewportMainAxisExtent;
|
||||
}
|
||||
@@ -2,151 +2,214 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import 'box.dart';
|
||||
import 'sliver.dart';
|
||||
import 'sliver_multi_box_adaptor.dart';
|
||||
|
||||
abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAdaptor {
|
||||
RenderSliverFixedExtentBoxAdaptor({
|
||||
@required RenderSliverBoxChildManager childManager,
|
||||
class RenderSliverList extends RenderSliverMultiBoxAdaptor {
|
||||
RenderSliverList({
|
||||
@required RenderSliverBoxChildManager childManager
|
||||
}) : super(childManager: childManager);
|
||||
|
||||
/// The main-axis extent of each item.
|
||||
double get itemExtent;
|
||||
|
||||
@override
|
||||
void performLayout() {
|
||||
assert(childManager.debugAssertChildListLocked());
|
||||
|
||||
final double itemExtent = this.itemExtent;
|
||||
double indexToScrollOffset(int index) => itemExtent * index;
|
||||
|
||||
final double scrollOffset = constraints.scrollOffset;
|
||||
double scrollOffset = constraints.scrollOffset;
|
||||
assert(scrollOffset >= 0.0);
|
||||
final double remainingPaintExtent = constraints.remainingPaintExtent;
|
||||
double remainingPaintExtent = constraints.remainingPaintExtent;
|
||||
assert(remainingPaintExtent >= 0.0);
|
||||
final double targetEndScrollOffset = scrollOffset + remainingPaintExtent;
|
||||
double targetEndScrollOffset = scrollOffset + remainingPaintExtent;
|
||||
BoxConstraints childConstraints = constraints.asBoxConstraints();
|
||||
int leadingGarbage = 0;
|
||||
int trailingGarbage = 0;
|
||||
bool reachedEnd = false;
|
||||
|
||||
BoxConstraints childConstraints = constraints.asBoxConstraints(
|
||||
minExtent: itemExtent,
|
||||
maxExtent: itemExtent,
|
||||
);
|
||||
|
||||
final int firstIndex = math.max(0, scrollOffset ~/ itemExtent);
|
||||
final int targetLastIndex = math.max(0, (targetEndScrollOffset / itemExtent).ceil() - 1);
|
||||
|
||||
if (firstChild != null) {
|
||||
final int oldFirstIndex = indexOf(firstChild);
|
||||
final int oldLastIndex = indexOf(lastChild);
|
||||
final int leadingGarbage = (firstIndex - oldFirstIndex).clamp(0, childCount);
|
||||
final int trailingGarbage = (oldLastIndex - targetLastIndex).clamp(0, childCount);
|
||||
if (leadingGarbage + trailingGarbage > 0)
|
||||
collectGarbage(leadingGarbage, trailingGarbage);
|
||||
}
|
||||
// This algorithm in principle is straight-forward: find the first child
|
||||
// that overlaps the given scrollOffset, creating more children at the top
|
||||
// of the list if necessary, then walk down the list updating and laying out
|
||||
// each child and adding more at the end if necessary until we have enough
|
||||
// children to cover the entire viewport.
|
||||
//
|
||||
// It is complicated by one minor issue, which is that any time you update
|
||||
// or create a child, it's possible that the some of the children that
|
||||
// haven't yet been laid out will be removed, leaving the list in an
|
||||
// inconsistent state, and requiring that missing nodes be recreated.
|
||||
//
|
||||
// To keep this mess tractable, this algorithm starts from what is currently
|
||||
// the first child, if any, and then walks up and/or down from there, so
|
||||
// that the nodes that might get removed are always at the edges of what has
|
||||
// already been laid out.
|
||||
|
||||
// Make sure we have at least one child to start from.
|
||||
if (firstChild == null) {
|
||||
if (!addInitialChild(index: firstIndex, scrollOffset: indexToScrollOffset(firstIndex))) {
|
||||
if (!addInitialChild()) {
|
||||
// There are no children.
|
||||
geometry = SliverGeometry.zero;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
RenderBox trailingChildWithLayout;
|
||||
// We have at least one child.
|
||||
|
||||
for (int index = indexOf(firstChild) - 1; index >= firstIndex; --index) {
|
||||
final RenderBox child = insertAndLayoutLeadingChild(childConstraints);
|
||||
final SliverMultiBoxAdaptorParentData childParentData = child.parentData;
|
||||
childParentData.scrollOffset = indexToScrollOffset(index);
|
||||
assert(childParentData.index == index);
|
||||
trailingChildWithLayout ??= child;
|
||||
}
|
||||
// These variables track the range of children that we have laid out. Within
|
||||
// this range, the children have consecutive indices. Outside this range,
|
||||
// it's possible for a child to get removed without notice.
|
||||
RenderBox leadingChildWithLayout, trailingChildWithLayout;
|
||||
|
||||
assert(childScrollOffset(firstChild) <= scrollOffset);
|
||||
|
||||
if (trailingChildWithLayout == null) {
|
||||
firstChild.layout(childConstraints);
|
||||
trailingChildWithLayout = firstChild;
|
||||
}
|
||||
|
||||
while (indexOf(trailingChildWithLayout) < targetLastIndex) {
|
||||
RenderBox child = childAfter(trailingChildWithLayout);
|
||||
if (child == null) {
|
||||
child = insertAndLayoutChild(childConstraints, after: trailingChildWithLayout);
|
||||
if (child == null) {
|
||||
// We have run out of children.
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
child.layout(childConstraints);
|
||||
// Find the last child that is at or before the scrollOffset.
|
||||
RenderBox earliestUsefulChild = firstChild;
|
||||
for (double earliestScrollOffset = childScrollOffset(earliestUsefulChild);
|
||||
earliestScrollOffset > scrollOffset;
|
||||
earliestScrollOffset = childScrollOffset(earliestUsefulChild)) {
|
||||
// We have to add children before the earliestUsefulChild.
|
||||
earliestUsefulChild = insertAndLayoutLeadingChild(childConstraints, parentUsesSize: true);
|
||||
if (earliestUsefulChild == null) {
|
||||
// We ran out of children before reaching the scroll offset.
|
||||
// We must inform our parent that this sliver cannot fulfill
|
||||
// its contract and that we need a scroll offset correction.
|
||||
geometry = new SliverGeometry(
|
||||
scrollOffsetCorrection: -childScrollOffset(firstChild),
|
||||
);
|
||||
return;
|
||||
}
|
||||
final SliverMultiBoxAdaptorParentData childParentData = earliestUsefulChild.parentData;
|
||||
childParentData.scrollOffset = earliestScrollOffset - paintExtentOf(firstChild);
|
||||
assert(earliestUsefulChild == firstChild);
|
||||
leadingChildWithLayout = earliestUsefulChild;
|
||||
trailingChildWithLayout ??= earliestUsefulChild;
|
||||
}
|
||||
|
||||
// At this point, earliestUsefulChild is the first child, and is a child
|
||||
// whose scrollOffset is at or before the scrollOffset, and
|
||||
// leadingChildWithLayout and trailingChildWithLayout are either null or
|
||||
// cover a range of render boxes that we have laid out with the first being
|
||||
// the same as earliestUsefulChild and the last being either at or after the
|
||||
// scroll offset.
|
||||
|
||||
assert(earliestUsefulChild == firstChild);
|
||||
assert(childScrollOffset(earliestUsefulChild) <= scrollOffset);
|
||||
|
||||
// Make sure we've laid out at least one child.
|
||||
if (leadingChildWithLayout == null) {
|
||||
earliestUsefulChild.layout(childConstraints, parentUsesSize: true);
|
||||
leadingChildWithLayout = earliestUsefulChild;
|
||||
trailingChildWithLayout = earliestUsefulChild;
|
||||
}
|
||||
|
||||
// Here, earliestUsefulChild is still the first child, it's got a
|
||||
// scrollOffset that is at or before our actual scrollOffset, and it has
|
||||
// been laid out, and is in fact our leadingChildWithLayout. It's possible
|
||||
// that some children beyond that one have also been laid out.
|
||||
|
||||
bool inLayoutRange = true;
|
||||
RenderBox child = earliestUsefulChild;
|
||||
int index = indexOf(child);
|
||||
double endScrollOffset = childScrollOffset(child) + paintExtentOf(child);
|
||||
bool advance() { // returns true if we advanced, false if we have no more children
|
||||
// This function is used in two different places below, to avoid code duplication.
|
||||
assert(child != null);
|
||||
if (child == trailingChildWithLayout)
|
||||
inLayoutRange = false;
|
||||
child = childAfter(child);
|
||||
if (child == null)
|
||||
inLayoutRange = false;
|
||||
index += 1;
|
||||
if (!inLayoutRange) {
|
||||
if (child == null || indexOf(child) != index) {
|
||||
// We are missing a child. Insert it (and lay it out) if possible.
|
||||
child = insertAndLayoutChild(childConstraints,
|
||||
after: trailingChildWithLayout,
|
||||
parentUsesSize: true,
|
||||
);
|
||||
if (child == null) {
|
||||
// We have run out of children.
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Lay out the child.
|
||||
child.layout(childConstraints, parentUsesSize: true);
|
||||
}
|
||||
trailingChildWithLayout = child;
|
||||
}
|
||||
trailingChildWithLayout = child;
|
||||
assert(child != null);
|
||||
final SliverMultiBoxAdaptorParentData childParentData = child.parentData;
|
||||
childParentData.scrollOffset = indexToScrollOffset(childParentData.index);
|
||||
childParentData.scrollOffset = endScrollOffset;
|
||||
assert(childParentData.index == index);
|
||||
endScrollOffset = childScrollOffset(child) + paintExtentOf(child);
|
||||
return true;
|
||||
}
|
||||
|
||||
final int lastIndex = indexOf(lastChild);
|
||||
final double leadingScrollOffset = indexToScrollOffset(firstIndex);
|
||||
final double trailingScrollOffset = indexToScrollOffset(lastIndex + 1);
|
||||
// Find the first child that ends after the scroll offset.
|
||||
while (endScrollOffset < scrollOffset) {
|
||||
leadingGarbage += 1;
|
||||
if (!advance()) {
|
||||
assert(leadingGarbage == childCount);
|
||||
assert(child == null);
|
||||
// we want to make sure we keep the last child around so we know the end scroll offset
|
||||
collectGarbage(leadingGarbage - 1, 0);
|
||||
assert(firstChild == lastChild);
|
||||
final double extent = childScrollOffset(lastChild) + paintExtentOf(lastChild);
|
||||
geometry = new SliverGeometry(
|
||||
scrollExtent: extent,
|
||||
paintExtent: 0.0,
|
||||
maxPaintExtent: extent,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Now find the first child that ends after our end.
|
||||
while (endScrollOffset < targetEndScrollOffset) {
|
||||
if (!advance()) {
|
||||
reachedEnd = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally count up all the remaining children and label them as garbage.
|
||||
if (child != null) {
|
||||
child = childAfter(child);
|
||||
while (child != null) {
|
||||
trailingGarbage += 1;
|
||||
child = childAfter(child);
|
||||
}
|
||||
}
|
||||
|
||||
// At this point everything should be good to go, we just have to clean up
|
||||
// the garbage and report the geometry.
|
||||
|
||||
collectGarbage(leadingGarbage, trailingGarbage);
|
||||
|
||||
assert(debugAssertChildListIsNonEmptyAndContiguous());
|
||||
assert(indexOf(firstChild) == firstIndex);
|
||||
assert(lastIndex <= targetLastIndex);
|
||||
|
||||
final double estimatedMaxScrollOffset = childManager.estimateMaxScrollOffset(
|
||||
constraints,
|
||||
firstIndex: firstIndex,
|
||||
lastIndex: lastIndex,
|
||||
leadingScrollOffset: leadingScrollOffset,
|
||||
trailingScrollOffset: trailingScrollOffset,
|
||||
);
|
||||
|
||||
double estimatedMaxScrollOffset;
|
||||
if (reachedEnd) {
|
||||
estimatedMaxScrollOffset = endScrollOffset;
|
||||
} else {
|
||||
estimatedMaxScrollOffset = childManager.estimateMaxScrollOffset(
|
||||
constraints,
|
||||
firstIndex: indexOf(firstChild),
|
||||
lastIndex: indexOf(lastChild),
|
||||
leadingScrollOffset: childScrollOffset(firstChild),
|
||||
trailingScrollOffset: endScrollOffset,
|
||||
);
|
||||
assert(estimatedMaxScrollOffset >= endScrollOffset - childScrollOffset(firstChild));
|
||||
}
|
||||
final double paintedExtent = calculatePaintOffset(
|
||||
constraints,
|
||||
from: leadingScrollOffset,
|
||||
to: trailingScrollOffset,
|
||||
from: childScrollOffset(firstChild),
|
||||
to: endScrollOffset,
|
||||
);
|
||||
|
||||
geometry = new SliverGeometry(
|
||||
scrollExtent: estimatedMaxScrollOffset,
|
||||
paintExtent: paintedExtent,
|
||||
maxPaintExtent: estimatedMaxScrollOffset,
|
||||
// Conservative to avoid flickering away the clip during scroll.
|
||||
hasVisualOverflow: lastIndex >= targetLastIndex || constraints.scrollOffset > 0.0,
|
||||
hasVisualOverflow: endScrollOffset > targetEndScrollOffset || constraints.scrollOffset > 0.0,
|
||||
);
|
||||
|
||||
assert(childManager.debugAssertChildListLocked());
|
||||
}
|
||||
}
|
||||
|
||||
class RenderSliverList extends RenderSliverFixedExtentBoxAdaptor {
|
||||
RenderSliverList({
|
||||
@required RenderSliverBoxChildManager childManager,
|
||||
double itemExtent,
|
||||
}) : _itemExtent = itemExtent, super(childManager: childManager);
|
||||
|
||||
@override
|
||||
double get itemExtent => _itemExtent;
|
||||
double _itemExtent;
|
||||
set itemExtent (double newValue) {
|
||||
assert(newValue != null);
|
||||
if (_itemExtent == newValue)
|
||||
return;
|
||||
_itemExtent = newValue;
|
||||
markNeedsLayout();
|
||||
}
|
||||
}
|
||||
|
||||
class RenderSliverFill extends RenderSliverFixedExtentBoxAdaptor {
|
||||
RenderSliverFill({
|
||||
@required RenderSliverBoxChildManager childManager,
|
||||
}) : super(childManager: childManager);
|
||||
|
||||
@override
|
||||
double get itemExtent => constraints.viewportMainAxisExtent;
|
||||
}
|
||||
|
||||
@@ -1482,14 +1482,12 @@ class SliverPadding extends SingleChildRenderObjectWidget {
|
||||
|
||||
/// A widget that uses the block layout algorithm for its children.
|
||||
///
|
||||
/// This widget is rarely used directly. Instead, consider using [Block], which
|
||||
/// combines the block layout algorithm with scrolling behavior.
|
||||
/// This widget is rarely used directly. Instead, consider using [SliverList],
|
||||
/// which combines a similar layout algorithm with scrolling behavior, or
|
||||
/// [Column], which gives you more flexible control over the layout of a
|
||||
/// vertical set of boxes.
|
||||
///
|
||||
/// For details about the block layout algorithm, see [RenderBlockBase].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Block], which combines block layout with scrolling.
|
||||
class BlockBody extends MultiChildRenderObjectWidget {
|
||||
/// Creates a block layout widget.
|
||||
///
|
||||
@@ -2001,7 +1999,7 @@ class GridPlacementData<DataType> extends ParentDataWidget<GridRenderObjectWidge
|
||||
/// The [Flex] widget does not scroll (and in general it is considered an error
|
||||
/// to have more children in a [Flex] than will fit in the available room). If
|
||||
/// you have some widgets and want them to be able to scroll if there is
|
||||
/// insufficient room, consider using a [Block].
|
||||
/// insufficient room, consider using a [ScrollList].
|
||||
///
|
||||
/// If you only have one child, then rather than using [Flex], [Row], or
|
||||
/// [Column], consider using [Align] or [Center] to position the child.
|
||||
@@ -2130,7 +2128,7 @@ class Flex extends MultiChildRenderObjectWidget {
|
||||
/// The [Row] widget does not scroll (and in general it is considered an error
|
||||
/// to have more children in a [Row] than will fit in the available room). If
|
||||
/// you have a line of widgets and want them to be able to scroll if there is
|
||||
/// insufficient room, consider using a [Block].
|
||||
/// insufficient room, consider using a [ScrollList].
|
||||
///
|
||||
/// For a vertical variant, see [Column].
|
||||
///
|
||||
@@ -2201,7 +2199,7 @@ class Row extends Flex {
|
||||
/// The [Column] widget does not scroll (and in general it is considered an error
|
||||
/// to have more children in a [Column] than will fit in the available room). If
|
||||
/// you have a line of widgets and want them to be able to scroll if there is
|
||||
/// insufficient room, consider using a [Block].
|
||||
/// insufficient room, consider using a [ScrollList].
|
||||
///
|
||||
/// For a horizontal variant, see [Row].
|
||||
///
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// DELETE THIS FILE WHEN REMOVING LEGACY SCROLLING CODE
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/rendering.dart';
|
||||
|
||||
@@ -173,12 +173,12 @@ class ListView extends BoxScrollView {
|
||||
@override
|
||||
Widget buildChildLayout(BuildContext context) {
|
||||
if (itemExtent != null) {
|
||||
return new SliverList(
|
||||
return new SliverFixedExtentList(
|
||||
delegate: childrenDelegate,
|
||||
itemExtent: itemExtent,
|
||||
);
|
||||
}
|
||||
return new SliverBlock(delegate: childrenDelegate);
|
||||
return new SliverList(delegate: childrenDelegate);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// DELETE THIS FILE WHEN REMOVING LEGACY SCROLLING CODE
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:collection/collection.dart' show lowerBound;
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// DELETE THIS FILE WHEN REMOVING LEGACY SCROLLING CODE
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
@@ -44,7 +44,7 @@ abstract class SliverChildDelegate {
|
||||
// ///
|
||||
// /// In general building all the widgets in advance is not efficient. It is
|
||||
// /// better to create a delegate that builds them on demand by subclassing
|
||||
// /// [SliverBlockDelegate] directly.
|
||||
// /// [SliverChildDelegate] directly.
|
||||
// ///
|
||||
// /// This class is provided for the cases where either the list of children is
|
||||
// /// known well in advance (ideally the children are themselves compile-time
|
||||
@@ -114,21 +114,21 @@ abstract class SliverMultiBoxAdaptorWidget extends RenderObjectWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class SliverBlock extends SliverMultiBoxAdaptorWidget {
|
||||
SliverBlock({
|
||||
class SliverList extends SliverMultiBoxAdaptorWidget {
|
||||
SliverList({
|
||||
Key key,
|
||||
@required SliverChildDelegate delegate,
|
||||
}) : super(key: key, delegate: delegate);
|
||||
|
||||
@override
|
||||
RenderSliverBlock createRenderObject(BuildContext context) {
|
||||
RenderSliverList createRenderObject(BuildContext context) {
|
||||
final SliverMultiBoxAdaptorElement element = context;
|
||||
return new RenderSliverBlock(childManager: element);
|
||||
return new RenderSliverList(childManager: element);
|
||||
}
|
||||
}
|
||||
|
||||
class SliverList extends SliverMultiBoxAdaptorWidget {
|
||||
SliverList({
|
||||
class SliverFixedExtentList extends SliverMultiBoxAdaptorWidget {
|
||||
SliverFixedExtentList({
|
||||
Key key,
|
||||
@required SliverChildDelegate delegate,
|
||||
@required this.itemExtent,
|
||||
@@ -137,13 +137,13 @@ class SliverList extends SliverMultiBoxAdaptorWidget {
|
||||
final double itemExtent;
|
||||
|
||||
@override
|
||||
RenderSliverList createRenderObject(BuildContext context) {
|
||||
RenderSliverFixedExtentList createRenderObject(BuildContext context) {
|
||||
final SliverMultiBoxAdaptorElement element = context;
|
||||
return new RenderSliverList(childManager: element, itemExtent: itemExtent);
|
||||
return new RenderSliverFixedExtentList(childManager: element, itemExtent: itemExtent);
|
||||
}
|
||||
|
||||
@override
|
||||
void updateRenderObject(BuildContext context, RenderSliverList renderObject) {
|
||||
void updateRenderObject(BuildContext context, RenderSliverFixedExtentList renderObject) {
|
||||
renderObject.itemExtent = itemExtent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,8 @@ class _TableElementRow {
|
||||
/// A widget that uses the table layout algorithm for its children.
|
||||
///
|
||||
/// If you only have one row, the [Row] widget is more appropriate. If you only
|
||||
/// have one column, the [Block] or [Column] widgets will be more appropriate.
|
||||
/// have one column, the [SliverList] or [Column] widgets will be more
|
||||
/// appropriate.
|
||||
///
|
||||
/// Rows size vertically based on their contents. To control the column widths,
|
||||
/// use the [columnWidths] property.
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// DELETE THIS FILE WHEN REMOVING LEGACY SCROLLING CODE
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
@@ -13,12 +13,12 @@ class TestRenderSliverBoxChildManager extends RenderSliverBoxChildManager {
|
||||
this.children,
|
||||
});
|
||||
|
||||
RenderSliverBlock _renderObject;
|
||||
RenderSliverList _renderObject;
|
||||
List<RenderBox> children;
|
||||
|
||||
RenderSliverBlock createRenderObject() {
|
||||
RenderSliverList createRenderObject() {
|
||||
assert(_renderObject == null);
|
||||
_renderObject = new RenderSliverBlock(childManager: this);
|
||||
_renderObject = new RenderSliverList(childManager: this);
|
||||
return _renderObject;
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ class TestRenderSliverBoxChildManager extends RenderSliverBoxChildManager {
|
||||
}
|
||||
|
||||
void main() {
|
||||
test('RenderSliverBlock basic test - down', () {
|
||||
test('RenderSliverList basic test - down', () {
|
||||
RenderObject inner;
|
||||
RenderBox a, b, c, d, e;
|
||||
TestRenderSliverBoxChildManager childManager = new TestRenderSliverBoxChildManager(
|
||||
@@ -136,7 +136,7 @@ void main() {
|
||||
expect(e.attached, false);
|
||||
});
|
||||
|
||||
test('RenderSliverBlock basic test - up', () {
|
||||
test('RenderSliverList basic test - up', () {
|
||||
RenderObject inner;
|
||||
RenderBox a, b, c, d, e;
|
||||
TestRenderSliverBoxChildManager childManager = new TestRenderSliverBoxChildManager(
|
||||
|
||||
@@ -134,13 +134,13 @@ void main() {
|
||||
|
||||
await tester.pumpWidget(new TestScrollable(
|
||||
slivers: <Widget>[
|
||||
new SliverBlock(
|
||||
new SliverList(
|
||||
delegate: delegate,
|
||||
),
|
||||
],
|
||||
));
|
||||
|
||||
final SliverMultiBoxAdaptorElement element = tester.element(find.byType(SliverBlock));
|
||||
final SliverMultiBoxAdaptorElement element = tester.element(find.byType(SliverList));
|
||||
|
||||
final double maxScrollOffset = element.estimateMaxScrollOffset(
|
||||
null,
|
||||
|
||||
@@ -27,7 +27,7 @@ Future<Null> test(WidgetTester tester, double offset, List<int> keys) {
|
||||
return tester.pumpWidget(new Viewport2(
|
||||
offset: new ViewportOffset.fixed(offset),
|
||||
slivers: <Widget>[
|
||||
new SliverBlock(
|
||||
new SliverList(
|
||||
delegate: new SliverChildListDelegate(keys.map((int key) {
|
||||
return new SizedBox(key: new GlobalObjectKey(key), height: 100.0, child: new GenerationText(key));
|
||||
}).toList()),
|
||||
|
||||
@@ -12,7 +12,7 @@ Future<Null> test(WidgetTester tester, double offset) {
|
||||
return tester.pumpWidget(new Viewport2(
|
||||
offset: new ViewportOffset.fixed(offset),
|
||||
slivers: <Widget>[
|
||||
new SliverBlock(
|
||||
new SliverList(
|
||||
delegate: new SliverChildListDelegate(<Widget>[
|
||||
new SizedBox(height: 400.0, child: new Text('a')),
|
||||
new SizedBox(height: 400.0, child: new Text('b')),
|
||||
@@ -77,7 +77,7 @@ void main() {
|
||||
await tester.pumpWidget(new Viewport2(
|
||||
offset: offset,
|
||||
slivers: <Widget>[
|
||||
new SliverBlock(
|
||||
new SliverList(
|
||||
delegate: new SliverChildListDelegate(<Widget>[
|
||||
new SizedBox(height: 251.0, child: new Text('a')),
|
||||
new SizedBox(height: 252.0, child: new Text('b')),
|
||||
@@ -94,7 +94,7 @@ void main() {
|
||||
await tester.pumpWidget(new Viewport2(
|
||||
offset: offset,
|
||||
slivers: <Widget>[
|
||||
new SliverBlock(
|
||||
new SliverList(
|
||||
delegate: new SliverChildListDelegate(<Widget>[
|
||||
new SizedBox(key: key1, height: 253.0, child: new Text('c')),
|
||||
new SizedBox(height: 251.0, child: new Text('a')),
|
||||
@@ -111,7 +111,7 @@ void main() {
|
||||
await tester.pumpWidget(new Viewport2(
|
||||
offset: offset,
|
||||
slivers: <Widget>[
|
||||
new SliverBlock(
|
||||
new SliverList(
|
||||
delegate: new SliverChildListDelegate(<Widget>[
|
||||
new SizedBox(height: 251.0, child: new Text('a')),
|
||||
new SizedBox(key: key1, height: 253.0, child: new Text('c')),
|
||||
@@ -128,7 +128,7 @@ void main() {
|
||||
await tester.pumpWidget(new Viewport2(
|
||||
offset: offset,
|
||||
slivers: <Widget>[
|
||||
new SliverBlock(
|
||||
new SliverList(
|
||||
delegate: new SliverChildListDelegate(<Widget>[
|
||||
new SizedBox(height: 251.0, child: new Text('a')),
|
||||
new SizedBox(height: 252.0, child: new Text('b')),
|
||||
@@ -143,7 +143,7 @@ void main() {
|
||||
await tester.pumpWidget(new Viewport2(
|
||||
offset: offset,
|
||||
slivers: <Widget>[
|
||||
new SliverBlock(
|
||||
new SliverList(
|
||||
delegate: new SliverChildListDelegate(<Widget>[
|
||||
new SizedBox(height: 251.0, child: new Text('a')),
|
||||
new SizedBox(key: key1, height: 253.0, child: new Text('c')),
|
||||
@@ -209,7 +209,7 @@ void main() {
|
||||
await tester.pumpWidget(new Viewport2(
|
||||
offset: new ViewportOffset.zero(),
|
||||
slivers: <Widget>[
|
||||
new SliverBlock(
|
||||
new SliverList(
|
||||
delegate: new SliverChildListDelegate(<Widget>[
|
||||
new SizedBox(height: 400.0, child: new Text('a')),
|
||||
]),
|
||||
@@ -222,7 +222,7 @@ void main() {
|
||||
await tester.pumpWidget(new Viewport2(
|
||||
offset: new ViewportOffset.fixed(100.0),
|
||||
slivers: <Widget>[
|
||||
new SliverBlock(
|
||||
new SliverList(
|
||||
delegate: new SliverChildListDelegate(<Widget>[
|
||||
new SizedBox(height: 400.0, child: new Text('a')),
|
||||
]),
|
||||
@@ -235,7 +235,7 @@ void main() {
|
||||
await tester.pumpWidget(new Viewport2(
|
||||
offset: new ViewportOffset.fixed(100.0),
|
||||
slivers: <Widget>[
|
||||
new SliverBlock(
|
||||
new SliverList(
|
||||
delegate: new SliverChildListDelegate(<Widget>[
|
||||
new SizedBox(height: 4000.0, child: new Text('a')),
|
||||
]),
|
||||
@@ -248,7 +248,7 @@ void main() {
|
||||
await tester.pumpWidget(new Viewport2(
|
||||
offset: new ViewportOffset.zero(),
|
||||
slivers: <Widget>[
|
||||
new SliverBlock(
|
||||
new SliverList(
|
||||
delegate: new SliverChildListDelegate(<Widget>[
|
||||
new SizedBox(height: 4000.0, child: new Text('a')),
|
||||
]),
|
||||
|
||||
@@ -117,7 +117,7 @@ void main() {
|
||||
new SliverToBoxAdapter(child: new Container(height: 520.0)),
|
||||
new SliverAppBar(delegate: new TestSliverAppBarDelegate(150.0), floating: true),
|
||||
new SliverToBoxAdapter(child: new Container(height: 5.0)),
|
||||
new SliverBlock(
|
||||
new SliverList(
|
||||
delegate: new SliverChildListDelegate(<Widget>[
|
||||
new Container(height: 50.0),
|
||||
new Container(height: 50.0),
|
||||
|
||||
Reference in New Issue
Block a user