提交 fbfbd57f 编写于 作者: A Adam Barth

Add CustomOneChildLayout

A CustomOneChildLayout is a widget that lets you perform a custom layout in the
simplified setting of sizing and positioning a single child.
上级 ee995e31
......@@ -205,6 +205,71 @@ class RenderPositionedBox extends RenderShiftedBox {
String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}alignment: $alignment\n';
}
/// A delegate for computing the layout of a render object with a single child.
class OneChildLayoutDelegate {
/// Returns the size of this object given the incomming constraints.
Size getSize(BoxConstraints constraints) => constraints.biggest;
/// Returns the box constraints for the child given the incomming constraints.
BoxConstraints getConstraintsForChild(BoxConstraints constraints) => constraints;
/// Returns the position where the child should be placed given the size of this object and the size of the child.
Point getPositionForChild(Size size, Size childSize) => Point.origin;
}
class RenderCustomOneChildLayoutBox extends RenderShiftedBox {
RenderCustomOneChildLayoutBox({
RenderBox child,
OneChildLayoutDelegate delegate
}) : _delegate = delegate, super(child) {
assert(delegate != null);
}
OneChildLayoutDelegate get delegate => _delegate;
OneChildLayoutDelegate _delegate;
void set delegate (OneChildLayoutDelegate newDelegate) {
assert(newDelegate != null);
if (_delegate == newDelegate)
return;
_delegate = newDelegate;
markNeedsLayout();
}
Size _getSize(BoxConstraints constraints) {
return constraints.constrain(_delegate.getSize(constraints));
}
double getMinIntrinsicWidth(BoxConstraints constraints) {
return _getSize(constraints).width;
}
double getMaxIntrinsicWidth(BoxConstraints constraints) {
return _getSize(constraints).width;
}
double getMinIntrinsicHeight(BoxConstraints constraints) {
return _getSize(constraints).height;
}
double getMaxIntrinsicHeight(BoxConstraints constraints) {
return _getSize(constraints).height;
}
bool get sizedByParent => true;
void performResize() {
size = _getSize(constraints);
}
void performLayout() {
if (child != null) {
child.layout(delegate.getConstraintsForChild(constraints), parentUsesSize: true);
final BoxParentData childParentData = child.parentData;
childParentData.position = delegate.getPositionForChild(size, child.size);
}
}
}
class RenderBaseline extends RenderShiftedBox {
RenderBaseline({
......
......@@ -35,6 +35,7 @@ export 'package:flutter/rendering.dart' show
LinearGradient,
Matrix4,
Offset,
OneChildLayoutDelegate,
Paint,
Path,
PlainTextSpan,
......@@ -139,13 +140,21 @@ class CustomPaint extends OneChildRenderObjectWidget {
assert(onPaint != null);
}
/// This widget repaints whenver you supply a new onPaint callback.
///
/// If you use an anonymous closure for the onPaint callback, you'll trigger
/// a repaint every time you build this widget, which might not be what you
/// intend. Instead, consider passing a reference to a member function, which
/// has a more stable identity.
final CustomPaintCallback onPaint;
final Object token; // set this to be repainted automatically when the token changes
/// This widget repaints whenever you supply a new token.
final Object token;
RenderCustomPaint createRenderObject() => new RenderCustomPaint(onPaint: onPaint);
void updateRenderObject(RenderCustomPaint renderObject, CustomPaint oldWidget) {
if (oldWidget != null && oldWidget.token != token)
if (oldWidget.token != token)
renderObject.markNeedsPaint();
renderObject.onPaint = onPaint;
}
......@@ -243,6 +252,35 @@ class Center extends Align {
: super(key: key, shrinkWrap: shrinkWrap, child: child);
}
class CustomOneChildLayout extends OneChildRenderObjectWidget {
CustomOneChildLayout({
Key key,
this.delegate,
this.token,
Widget child
}) : super(key: key, child: child) {
assert(delegate != null);
}
/// A long-lived delegate that controls the layout of this widget.
///
/// Whenever the delegate changes, we need to recompute the layout of this
/// widget, which means you might not want to create a new delegate instance
/// every time you build this widget. Instead, consider using a long-lived
/// deletate (perhaps held in a component's state) that you re-use every time
/// you build this widget.
final OneChildLayoutDelegate delegate;
final Object token;
RenderCustomOneChildLayoutBox createRenderObject() => new RenderCustomOneChildLayoutBox(delegate: delegate);
void updateRenderObject(RenderCustomOneChildLayoutBox renderObject, CustomOneChildLayout oldWidget) {
if (oldWidget.token != token)
renderObject.markNeedsLayout();
renderObject.delegate = delegate;
}
}
class SizedBox extends OneChildRenderObjectWidget {
SizedBox({ Key key, this.width, this.height, Widget child })
: super(key: key, child: child);
......
import 'package:flutter/widgets.dart';
import 'package:test/test.dart';
import 'widget_tester.dart';
class TestOneChildLayoutDelegate extends OneChildLayoutDelegate {
BoxConstraints constraintsFromGetSize;
BoxConstraints constraintsFromGetConstraintsForChild;
Size sizeFromGetPositionForChild;
Size childSizeFromGetPositionForChild;
Size getSize(BoxConstraints constraints) {
constraintsFromGetSize = constraints;
return new Size(200.0, 300.0);
}
BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
constraintsFromGetConstraintsForChild = constraints;
return new BoxConstraints(
minWidth: 100.0,
maxWidth: 150.0,
minHeight: 200.0,
maxHeight: 400.0
);
}
Point getPositionForChild(Size size, Size childSize) {
sizeFromGetPositionForChild = size;
childSizeFromGetPositionForChild = childSize;
return Point.origin;
}
}
void main() {
test('Control test for CustomOneChildLayout', () {
testWidgets((WidgetTester tester) {
TestOneChildLayoutDelegate delegate = new TestOneChildLayoutDelegate();
tester.pumpWidget(new Center(
child: new CustomOneChildLayout(delegate: delegate, child: new Container())
));
expect(delegate.constraintsFromGetSize.minWidth, 0.0);
expect(delegate.constraintsFromGetSize.maxWidth, 800.0);
expect(delegate.constraintsFromGetSize.minHeight, 0.0);
expect(delegate.constraintsFromGetSize.maxHeight, 600.0);
expect(delegate.constraintsFromGetConstraintsForChild.minWidth, 0.0);
expect(delegate.constraintsFromGetConstraintsForChild.maxWidth, 800.0);
expect(delegate.constraintsFromGetConstraintsForChild.minHeight, 0.0);
expect(delegate.constraintsFromGetConstraintsForChild.maxHeight, 600.0);
expect(delegate.sizeFromGetPositionForChild.width, 200.0);
expect(delegate.sizeFromGetPositionForChild.height, 300.0);
expect(delegate.childSizeFromGetPositionForChild.width, 150.0);
expect(delegate.childSizeFromGetPositionForChild.height, 400.0);
});
});
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册