mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Move VariableHeightScrollable to sdk/lib/widgets
Added a callback to BlockViewport so that the scrollable can stay in sync with the viewport's contents. R=ianh@google.com Review URL: https://codereview.chromium.org/1227823012 .
This commit is contained in:
parent
442c55b4c4
commit
63318886a0
@ -87,6 +87,7 @@ dart_pkg("sky") {
|
||||
"lib/widgets/theme.dart",
|
||||
"lib/widgets/toggleable.dart",
|
||||
"lib/widgets/tool_bar.dart",
|
||||
"lib/widgets/variable_height_scrollable.dart",
|
||||
"lib/widgets/widget.dart",
|
||||
"pubspec.yaml",
|
||||
]
|
||||
|
||||
@ -6,16 +6,14 @@ import 'dart:sky' as sky;
|
||||
|
||||
import 'package:vector_math/vector_math.dart';
|
||||
import 'package:sky/animation/animation_performance.dart';
|
||||
import 'package:sky/animation/scroll_behavior.dart';
|
||||
import 'package:sky/base/lerp.dart';
|
||||
import 'package:sky/painting/text_style.dart';
|
||||
import 'package:sky/theme/colors.dart';
|
||||
import 'package:sky/widgets/animation_builder.dart';
|
||||
import 'package:sky/widgets/basic.dart';
|
||||
import 'package:sky/widgets/block_viewport.dart';
|
||||
import 'package:sky/widgets/card.dart';
|
||||
import 'package:sky/widgets/scaffold.dart';
|
||||
import 'package:sky/widgets/scrollable.dart';
|
||||
import 'package:sky/widgets/variable_height_scrollable.dart';
|
||||
import 'package:sky/widgets/theme.dart';
|
||||
import 'package:sky/widgets/tool_bar.dart';
|
||||
import 'package:sky/widgets/widget.dart';
|
||||
@ -26,50 +24,13 @@ const double _kMinFlingVelocity = 700.0;
|
||||
const double _kMinFlingVelocityDelta = 400.0;
|
||||
const double _kDismissCardThreshold = 0.6;
|
||||
|
||||
class VariableHeightScrollable extends Scrollable {
|
||||
VariableHeightScrollable({
|
||||
String key,
|
||||
this.builder,
|
||||
this.token
|
||||
}) : super(key: key);
|
||||
|
||||
IndexedBuilder builder;
|
||||
Object token;
|
||||
|
||||
void syncFields(VariableHeightScrollable source) {
|
||||
builder = source.builder;
|
||||
token = source.token;
|
||||
super.syncFields(source);
|
||||
}
|
||||
|
||||
ScrollBehavior createScrollBehavior() => new OverscrollBehavior();
|
||||
OverscrollBehavior get scrollBehavior => super.scrollBehavior;
|
||||
|
||||
void _handleSizeChanged(Size newSize) {
|
||||
setState(() {
|
||||
scrollBehavior.containerSize = newSize.height;
|
||||
scrollBehavior.contentsSize = 5000.0;
|
||||
});
|
||||
}
|
||||
|
||||
Widget buildContent() {
|
||||
return new SizeObserver(
|
||||
callback: _handleSizeChanged,
|
||||
child: new BlockViewport(
|
||||
builder: builder,
|
||||
startOffset: scrollOffset,
|
||||
token: token
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CardCollectionApp extends App {
|
||||
|
||||
final TextStyle cardLabelStyle =
|
||||
new TextStyle(color: White, fontSize: 18.0, fontWeight: bold);
|
||||
|
||||
final List<double> cardHeights = [
|
||||
48.0, 64.0, 82.0, 46.0, 60.0, 55.0, 84.0, 96.0, 50.0,
|
||||
48.0, 64.0, 82.0, 46.0, 60.0, 55.0, 84.0, 96.0, 50.0,
|
||||
48.0, 64.0, 82.0, 46.0, 60.0, 55.0, 84.0, 96.0, 50.0,
|
||||
48.0, 64.0, 82.0, 46.0, 60.0, 55.0, 84.0, 96.0, 50.0
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:collection';
|
||||
|
||||
import '../rendering/block.dart';
|
||||
import '../rendering/box.dart';
|
||||
import '../rendering/object.dart';
|
||||
@ -10,6 +12,13 @@ import 'widget.dart';
|
||||
// return null if index is greater than index of last entry
|
||||
typedef Widget IndexedBuilder(int index);
|
||||
|
||||
typedef void LayoutChangedCallback(
|
||||
int firstVisibleChildIndex,
|
||||
int visibleChildCount,
|
||||
UnmodifiableListView<double> childOffsets,
|
||||
bool didReachLastChild
|
||||
);
|
||||
|
||||
class _Key {
|
||||
const _Key(this.type, this.key);
|
||||
factory _Key.fromWidget(Widget widget) => new _Key(widget.runtimeType, widget.key);
|
||||
@ -20,12 +29,13 @@ class _Key {
|
||||
}
|
||||
|
||||
class BlockViewport extends RenderObjectWrapper {
|
||||
BlockViewport({ this.builder, this.startOffset, this.token, String key })
|
||||
BlockViewport({ this.builder, this.startOffset, this.token, this.onLayoutChanged, String key })
|
||||
: super(key: key);
|
||||
|
||||
IndexedBuilder builder;
|
||||
double startOffset;
|
||||
Object token;
|
||||
LayoutChangedCallback onLayoutChanged;
|
||||
|
||||
RenderBlockViewport get root => super.root;
|
||||
RenderBlockViewport createNode() => new RenderBlockViewport();
|
||||
@ -83,6 +93,7 @@ class BlockViewport extends RenderObjectWrapper {
|
||||
List<double> _offsets = <double>[0.0];
|
||||
int _currentStartIndex = 0;
|
||||
int _currentChildCount = 0;
|
||||
bool _didReachLastChild = false;
|
||||
|
||||
int _findIndexForOffsetBeforeOrAt(double offset) {
|
||||
int left = 0;
|
||||
@ -113,6 +124,7 @@ class BlockViewport extends RenderObjectWrapper {
|
||||
builder = newNode.builder;
|
||||
token = newNode.token;
|
||||
_offsets = <double>[0.0];
|
||||
_didReachLastChild = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -196,6 +208,7 @@ class BlockViewport extends RenderObjectWrapper {
|
||||
haveChildren = true;
|
||||
} else {
|
||||
haveChildren = false;
|
||||
_didReachLastChild = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -207,8 +220,10 @@ class BlockViewport extends RenderObjectWrapper {
|
||||
// list is complete (and thus we are overscrolled).
|
||||
while (true) {
|
||||
Widget widget = _getWidget(startIndex, innerConstraints);
|
||||
if (widget == null)
|
||||
if (widget == null) {
|
||||
_didReachLastChild = true;
|
||||
break;
|
||||
}
|
||||
_Key widgetKey = new _Key.fromWidget(widget);
|
||||
if (_offsets.last > startOffset) {
|
||||
newChildren[widgetKey] = widget;
|
||||
@ -238,6 +253,7 @@ class BlockViewport extends RenderObjectWrapper {
|
||||
}
|
||||
}
|
||||
assert(haveChildren != null);
|
||||
assert(haveChildren || _didReachLastChild);
|
||||
|
||||
assert(startIndex >= 0);
|
||||
assert(startIndex < _offsets.length);
|
||||
@ -249,8 +265,10 @@ class BlockViewport extends RenderObjectWrapper {
|
||||
while (_offsets[index] < endOffset) {
|
||||
if (!builtChildren.containsKey(index)) {
|
||||
Widget widget = _getWidget(index, innerConstraints);
|
||||
if (widget == null)
|
||||
break; // reached the end of the list
|
||||
if (widget == null) {
|
||||
_didReachLastChild = true;
|
||||
break;
|
||||
}
|
||||
newChildren[new _Key.fromWidget(widget)] = widget;
|
||||
builtChildren[index] = widget;
|
||||
}
|
||||
@ -287,6 +305,15 @@ class BlockViewport extends RenderObjectWrapper {
|
||||
_childrenByKey = newChildren;
|
||||
_currentStartIndex = startIndex;
|
||||
_currentChildCount = _childrenByKey.length;
|
||||
|
||||
if (onLayoutChanged != null) {
|
||||
onLayoutChanged(
|
||||
_currentStartIndex,
|
||||
_currentChildCount,
|
||||
new UnmodifiableListView<double>(_offsets),
|
||||
_didReachLastChild
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
60
sdk/lib/widgets/variable_height_scrollable.dart
Normal file
60
sdk/lib/widgets/variable_height_scrollable.dart
Normal file
@ -0,0 +1,60 @@
|
||||
// Copyright 2015 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:collection';
|
||||
|
||||
import '../animation/scroll_behavior.dart';
|
||||
import 'basic.dart';
|
||||
import 'block_viewport.dart';
|
||||
import 'scrollable.dart';
|
||||
import 'widget.dart';
|
||||
|
||||
class VariableHeightScrollable extends Scrollable {
|
||||
VariableHeightScrollable({
|
||||
String key,
|
||||
this.builder,
|
||||
this.token
|
||||
}) : super(key: key);
|
||||
|
||||
IndexedBuilder builder;
|
||||
Object token;
|
||||
|
||||
void syncFields(VariableHeightScrollable source) {
|
||||
builder = source.builder;
|
||||
token = source.token;
|
||||
super.syncFields(source);
|
||||
}
|
||||
|
||||
ScrollBehavior createScrollBehavior() => new OverscrollBehavior();
|
||||
OverscrollBehavior get scrollBehavior => super.scrollBehavior;
|
||||
|
||||
void _handleSizeChanged(Size newSize) {
|
||||
setState(() {
|
||||
scrollBehavior.containerSize = newSize.height;
|
||||
});
|
||||
}
|
||||
|
||||
void _handleLayoutChanged(
|
||||
int firstVisibleChildIndex,
|
||||
int visibleChildCount,
|
||||
UnmodifiableListView<double> childOffsets,
|
||||
bool didReachLastChild) {
|
||||
assert(childOffsets.length > 0);
|
||||
scrollBehavior.contentsSize = didReachLastChild ? childOffsets.last : double.INFINITY;
|
||||
if (didReachLastChild && scrollOffset > scrollBehavior.maxScrollOffset)
|
||||
settleScrollOffset();
|
||||
}
|
||||
|
||||
Widget buildContent() {
|
||||
return new SizeObserver(
|
||||
callback: _handleSizeChanged,
|
||||
child: new BlockViewport(
|
||||
builder: builder,
|
||||
onLayoutChanged: _handleLayoutChanged,
|
||||
startOffset: scrollOffset,
|
||||
token: token
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user