mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
217 lines
6.3 KiB
Dart
217 lines
6.3 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/rendering/box.dart';
|
|
import 'package:sky/rendering/object.dart';
|
|
|
|
class BlockParentData extends BoxParentData with ContainerParentDataMixin<RenderBox> { }
|
|
|
|
abstract class RenderBlockBase extends RenderBox with ContainerRenderObjectMixin<RenderBox, BlockParentData>,
|
|
RenderBoxContainerDefaultsMixin<RenderBox, BlockParentData> {
|
|
|
|
// lays out RenderBox children in a vertical stack
|
|
// uses the maximum width provided by the parent
|
|
|
|
RenderBlockBase({
|
|
List<RenderBox> children
|
|
}) {
|
|
addAll(children);
|
|
}
|
|
|
|
void setupParentData(RenderBox child) {
|
|
if (child.parentData is! BlockParentData)
|
|
child.parentData = new BlockParentData();
|
|
}
|
|
|
|
double _childrenHeight;
|
|
double get childrenHeight => _childrenHeight;
|
|
|
|
void markNeedsLayout() {
|
|
_childrenHeight = null;
|
|
super.markNeedsLayout();
|
|
}
|
|
|
|
void performLayout() {
|
|
assert(constraints is BoxConstraints);
|
|
double width = constraints.constrainWidth(constraints.maxWidth);
|
|
BoxConstraints innerConstraints = new BoxConstraints.tightFor(width: width);
|
|
double y = 0.0;
|
|
RenderBox child = firstChild;
|
|
while (child != null) {
|
|
child.layout(innerConstraints, parentUsesSize: true);
|
|
assert(child.parentData is BlockParentData);
|
|
child.parentData.position = new Point(0.0, y);
|
|
y += child.size.height;
|
|
child = child.parentData.nextSibling;
|
|
}
|
|
_childrenHeight = y;
|
|
}
|
|
|
|
}
|
|
|
|
class RenderBlock extends RenderBlockBase {
|
|
|
|
// sizes itself to the height of its child stack
|
|
|
|
RenderBlock({ List<RenderBox> children }) : super(children: children);
|
|
|
|
double getMinIntrinsicWidth(BoxConstraints constraints) {
|
|
double width = 0.0;
|
|
BoxConstraints innerConstraints = constraints.widthConstraints();
|
|
RenderBox child = firstChild;
|
|
while (child != null) {
|
|
width = math.max(width, child.getMinIntrinsicWidth(innerConstraints));
|
|
assert(child.parentData is BlockParentData);
|
|
child = child.parentData.nextSibling;
|
|
}
|
|
return width;
|
|
}
|
|
|
|
double getMaxIntrinsicWidth(BoxConstraints constraints) {
|
|
double width = 0.0;
|
|
BoxConstraints innerConstraints = constraints.widthConstraints();
|
|
RenderBox child = firstChild;
|
|
while (child != null) {
|
|
width = math.max(width, child.getMaxIntrinsicWidth(innerConstraints));
|
|
assert(child.parentData is BlockParentData);
|
|
child = child.parentData.nextSibling;
|
|
}
|
|
return width;
|
|
}
|
|
|
|
double _getIntrinsicHeight(BoxConstraints constraints) {
|
|
double height = 0.0;
|
|
double width = constraints.constrainWidth(constraints.maxWidth);
|
|
BoxConstraints innerConstraints = new BoxConstraints.tightFor(width: width);
|
|
RenderBox child = firstChild;
|
|
while (child != null) {
|
|
double childHeight = child.getMinIntrinsicHeight(innerConstraints);
|
|
assert(childHeight == child.getMaxIntrinsicHeight(innerConstraints));
|
|
height += childHeight;
|
|
assert(child.parentData is BlockParentData);
|
|
child = child.parentData.nextSibling;
|
|
}
|
|
return height;
|
|
}
|
|
|
|
double getMinIntrinsicHeight(BoxConstraints constraints) {
|
|
return _getIntrinsicHeight(constraints);
|
|
}
|
|
|
|
double getMaxIntrinsicHeight(BoxConstraints constraints) {
|
|
return _getIntrinsicHeight(constraints);
|
|
}
|
|
|
|
double computeDistanceToActualBaseline(TextBaseline baseline) {
|
|
return defaultComputeDistanceToFirstActualBaseline(baseline);
|
|
}
|
|
|
|
void performLayout() {
|
|
assert(constraints.maxHeight >= double.INFINITY);
|
|
super.performLayout();
|
|
size = constraints.constrain(new Size(constraints.maxWidth, childrenHeight));
|
|
assert(!size.isInfinite);
|
|
}
|
|
|
|
void paint(PaintingCanvas canvas, Offset offset) {
|
|
defaultPaint(canvas, offset);
|
|
}
|
|
|
|
void hitTestChildren(HitTestResult result, { Point position }) {
|
|
defaultHitTestChildren(result, position: position);
|
|
}
|
|
|
|
}
|
|
|
|
class RenderBlockViewport extends RenderBlockBase {
|
|
|
|
// sizes itself to the given constraints
|
|
// at the start of layout, calls callback
|
|
|
|
RenderBlockViewport({
|
|
LayoutCallback callback,
|
|
List<RenderBox> children,
|
|
double startOffset: 0.0
|
|
}) : _callback = callback, _startOffset = startOffset, super(children: children);
|
|
|
|
bool _inCallback = false;
|
|
|
|
LayoutCallback _callback;
|
|
LayoutCallback get callback => _callback;
|
|
void set callback(LayoutCallback value) {
|
|
assert(!_inCallback);
|
|
if (value == _callback)
|
|
return;
|
|
_callback = value;
|
|
markNeedsLayout();
|
|
}
|
|
|
|
// you can set this from within the callback if necessary
|
|
double _startOffset;
|
|
double get startOffset => _startOffset;
|
|
void set startOffset(double value) {
|
|
if (value == _startOffset)
|
|
return;
|
|
_startOffset = value;
|
|
if (!_inCallback)
|
|
markNeedsPaint();
|
|
}
|
|
|
|
double getMinIntrinsicWidth(BoxConstraints constraints) {
|
|
return constraints.constrainWidth();
|
|
}
|
|
|
|
double getMaxIntrinsicWidth(BoxConstraints constraints) {
|
|
return constraints.constrainWidth();
|
|
}
|
|
|
|
double getMinIntrinsicHeight(BoxConstraints constraints) {
|
|
return constraints.constrainHeight();
|
|
}
|
|
|
|
double getMaxIntrinsicHeight(BoxConstraints constraints) {
|
|
return constraints.constrainHeight();
|
|
}
|
|
|
|
// We don't override computeDistanceToActualBaseline(), because we
|
|
// want the default behaviour (returning null). Otherwise, as you
|
|
// scroll the RenderBlockViewport, it would shift in its parent if
|
|
// the parent was baseline-aligned, which makes no sense.
|
|
|
|
bool get sizedByParent => true;
|
|
|
|
void performResize() {
|
|
size = constraints.biggest;
|
|
assert(!size.isInfinite);
|
|
}
|
|
|
|
bool get debugDoesLayoutWithCallback => true;
|
|
void performLayout() {
|
|
assert(constraints.maxHeight < double.INFINITY);
|
|
if (_callback != null) {
|
|
try {
|
|
_inCallback = true;
|
|
invokeLayoutCallback(_callback);
|
|
} finally {
|
|
_inCallback = false;
|
|
}
|
|
}
|
|
super.performLayout();
|
|
}
|
|
|
|
void paint(PaintingCanvas canvas, Offset offset) {
|
|
canvas.save();
|
|
canvas.clipRect(offset & size);
|
|
defaultPaint(canvas, offset.translate(0.0, startOffset));
|
|
canvas.restore();
|
|
}
|
|
|
|
void hitTestChildren(HitTestResult result, { Point position }) {
|
|
defaultHitTestChildren(result, position: position + new Offset(0.0, -startOffset));
|
|
}
|
|
|
|
}
|