mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
This fixes some theoretical bugs whereby we were using hashCode to try
to get unique keys for objects, but really we wanted object identity.
It also lays the groundwork for a new GlobalKey concept.
I tried to keep the impact on the code minimal, which is why the "Key"
constructor is actually a factory that returns a StringKey. The code
has this class hierarchy:
```
KeyBase
|
Key--------------+---------------+
| | |
StringKey ObjectKey UniqueKey
```
...where the constructors are Key and Key.stringify (StringKey),
Key.fromObjectIdentity (ObjectKey), and Key.unique (UniqueKey).
We could instead of factory methods use regular constructors with the
following hierarchy:
```
KeyBase
|
LocalKey---------+---------------+
| | |
Key ObjectIdentityKey UniqueKey
```
...with constructors Key, Key.stringify, ObjectIdentityKey, and
UniqueKey, but I felt that that was maybe a more confusing hierarchy.
I don't have a strong opinion on this.
107 lines
3.0 KiB
Dart
107 lines
3.0 KiB
Dart
// 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:math' as math;
|
|
|
|
import 'package:sky/animation/scroll_behavior.dart';
|
|
import 'package:sky/widgets/basic.dart';
|
|
import 'package:sky/widgets/scrollable.dart';
|
|
|
|
abstract class FixedHeightScrollable extends Scrollable {
|
|
|
|
FixedHeightScrollable({ Key key, this.itemHeight, this.padding })
|
|
: super(key: key) {
|
|
assert(itemHeight != null);
|
|
}
|
|
|
|
EdgeDims padding;
|
|
double itemHeight;
|
|
|
|
/// Subclasses must implement `get itemCount` to tell FixedHeightScrollable
|
|
/// how many items there are in the list.
|
|
int get itemCount;
|
|
int _previousItemCount;
|
|
|
|
void syncFields(FixedHeightScrollable source) {
|
|
padding = source.padding;
|
|
itemHeight = source.itemHeight;
|
|
super.syncFields(source);
|
|
}
|
|
|
|
ScrollBehavior createScrollBehavior() => new OverscrollBehavior();
|
|
OverscrollBehavior get scrollBehavior => super.scrollBehavior;
|
|
|
|
double _height;
|
|
void _handleSizeChanged(Size newSize) {
|
|
setState(() {
|
|
_height = newSize.height;
|
|
scrollBehavior.containerSize = _height;
|
|
});
|
|
}
|
|
|
|
void _updateContentsHeight() {
|
|
double contentsHeight = itemHeight * itemCount;
|
|
if (padding != null)
|
|
contentsHeight += padding.top + padding.bottom;
|
|
scrollBehavior.contentsSize = contentsHeight;
|
|
}
|
|
|
|
void _updateScrollOffset() {
|
|
if (scrollOffset > scrollBehavior.maxScrollOffset)
|
|
settleScrollOffset();
|
|
}
|
|
|
|
Widget buildContent() {
|
|
if (itemCount != _previousItemCount) {
|
|
_previousItemCount = itemCount;
|
|
_updateContentsHeight();
|
|
_updateScrollOffset();
|
|
}
|
|
|
|
int itemShowIndex = 0;
|
|
int itemShowCount = 0;
|
|
double offsetY = 0.0;
|
|
if (_height != null && _height > 0.0) {
|
|
if (scrollOffset < 0.0) {
|
|
double visibleHeight = _height + scrollOffset;
|
|
itemShowCount = (visibleHeight / itemHeight).round() + 1;
|
|
offsetY = scrollOffset;
|
|
} else {
|
|
itemShowCount = (_height / itemHeight).ceil();
|
|
double alignmentDelta = -scrollOffset % itemHeight;
|
|
double drawStart;
|
|
if (alignmentDelta != 0.0) {
|
|
alignmentDelta -= itemHeight;
|
|
itemShowCount += 1;
|
|
drawStart = scrollOffset + alignmentDelta;
|
|
offsetY = -alignmentDelta;
|
|
} else {
|
|
drawStart = scrollOffset;
|
|
}
|
|
itemShowIndex = math.max(0, (drawStart / itemHeight).floor());
|
|
}
|
|
}
|
|
|
|
List<Widget> items = buildItems(itemShowIndex, itemShowCount);
|
|
assert(items.every((item) => item.key != null));
|
|
|
|
// TODO(ianh): Refactor this so that it does the building in the
|
|
// same frame as the size observing, similar to BlockViewport, but
|
|
// keeping the fixed-height optimisations.
|
|
return new SizeObserver(
|
|
callback: _handleSizeChanged,
|
|
child: new Viewport(
|
|
offset: offsetY,
|
|
child: new Container(
|
|
padding: padding,
|
|
child: new Block(items)
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
List<Widget> buildItems(int start, int count);
|
|
|
|
}
|