flutter_flutter/framework/components/fixed_height_scrollable.dart
Adam Barth 1eb13d0112 Organize sky/framework/animation
This CL cleans up the sky/framework/animation as follows:

1) I've moved code that's used only by the custom elements framework into
   sky/framework/elements/animation. This code is based on AnimationDelegates
   rather than Streams.
2) Rename ScrollCurve to ScrollBehavior because it encapsulates more behavior
   than just a curve.
3) Make the Generator interface explicit and mark subclasses as actual
   subclasses.
4) Move Simulation into generators.dart because it implements the Generator
   interface.
5) Move Animation out of generators.dart because it does not implement the
   Generator interface.

R=eseidel@chromium.org

Review URL: https://codereview.chromium.org/1001373002
2015-03-13 10:04:56 -07:00

88 lines
2.5 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 '../animation/scroll_behavior.dart';
import '../fn.dart';
import 'dart:math' as math;
import 'dart:sky' as sky;
import 'scrollable.dart';
abstract class FixedHeightScrollable extends Scrollable {
// TODO(rafaelw): This component really shouldn't have an opinion
// about how it is sized. The owning component should decide whether
// it's explicitly sized or flexible or whatever...
static final Style _style = new Style('''
overflow: hidden;
position: relative;
flex: 1;
will-change: transform;'''
);
static final Style _scrollAreaStyle = new Style('''
position:relative;
will-change: transform;'''
);
double _height = 0.0;
double _itemHeight;
FixedHeightScrollable({
Object key,
ScrollBehavior scrollBehavior
}) : super(key: key, scrollBehavior: scrollBehavior);
void didMount() {
super.didMount();
var root = getRoot();
var item = root.firstChild.firstChild;
sky.ClientRect scrollRect = root.getBoundingClientRect();
sky.ClientRect itemRect = item.getBoundingClientRect();
assert(scrollRect.height > 0);
assert(itemRect.height > 0);
setState(() {
_height = scrollRect.height;
_itemHeight = itemRect.height;
});
}
Node build() {
var itemNumber = 0;
var drawCount = 1;
var transformStyle = '';
if (_height > 0.0) {
if (scrollOffset < 0.0) {
double visibleHeight = _height + scrollOffset;
drawCount = (visibleHeight / _itemHeight).round() + 1;
transformStyle =
'transform: translateY(${(-scrollOffset).toStringAsFixed(2)}px)';
} else {
drawCount = (_height / _itemHeight).round() + 1;
double alignmentOffset = math.max(0.0, scrollOffset);
double alignmentDelta = -scrollOffset % _itemHeight;
if (alignmentDelta != 0.0)
alignmentDelta -= _itemHeight;
double drawStart = scrollOffset + alignmentDelta;
itemNumber = (drawStart / _itemHeight).floor();
transformStyle =
'transform: translateY(${(alignmentDelta).toStringAsFixed(2)}px)';
}
}
return new Container(
styles: [_style],
children: [
new Container(
styles: [_scrollAreaStyle],
inlineStyle: transformStyle,
children: buildItems(itemNumber, drawCount)
)
]
);
}
}