Commit fcd47f84 authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

CustomPaint size (#6790)

parent 01a8d510
......@@ -1783,17 +1783,27 @@ abstract class CustomPainter {
/// tree as needing a new layout during the callback (the layout for this frame
/// has already happened).
///
/// Custom painters normally size themselves to their child. If they do not have
/// a child, they attempt to size themselves to the [preferredSize], which
/// defaults to [Size.zero].
///
/// See also:
///
/// * [CustomPainter]
/// * [Canvas]
/// * [CustomPainter], the class that custom painter delegates should extend.
/// * [Canvas], the API provided to custom painter delegates.
class RenderCustomPaint extends RenderProxyBox {
/// Creates a render object that delegates its painting.
RenderCustomPaint({
CustomPainter painter,
CustomPainter foregroundPainter,
RenderBox child
}) : _painter = painter, _foregroundPainter = foregroundPainter, super(child);
Size preferredSize: Size.zero,
RenderBox child,
}) : _painter = painter,
_foregroundPainter = foregroundPainter,
_preferredSize = preferredSize,
super(child) {
assert(preferredSize != null);
}
/// The background custom paint delegate.
///
......@@ -1860,6 +1870,23 @@ class RenderCustomPaint extends RenderProxyBox {
}
}
/// The size that this [RenderCustomPaint] should aim for, given the layout
/// constraints, if there is no child.
///
/// Defaults to [Size.zero].
///
/// If there's a child, this is ignored, and the size of the child is used
/// instead.
Size get preferredSize => _preferredSize;
Size _preferredSize;
set preferredSize (Size value) {
assert(value != null);
if (preferredSize == value)
return;
_preferredSize = value;
markNeedsLayout();
}
@override
void attach(PipelineOwner owner) {
super.attach(owner);
......@@ -1886,6 +1913,11 @@ class RenderCustomPaint extends RenderProxyBox {
return _painter != null && (_painter.hitTest(position) ?? true);
}
@override
void performResize() {
size = constraints.constrain(preferredSize);
}
void _paintWithPainter(Canvas canvas, Offset offset, CustomPainter painter) {
int debugPreviousCanvasSaveCount;
canvas.save();
......
......@@ -197,9 +197,13 @@ class BackdropFilter extends SingleChildRenderObjectWidget {
///
/// Painters are implemented by subclassing [CustomPainter].
///
/// Because custom paint calls its painters during paint, you cannot mark the
/// tree as needing a new layout during the callback (the layout for this frame
/// has already happened).
/// Because custom paint calls its painters during paint, you cannot call
/// `setState` or `markNeedsLayout` during the callback (the layout for this
/// frame has already happened).
///
/// Custom painters normally size themselves to their child. If they do not have
/// a child, they attempt to size themselves to the [size], which defaults to
/// [Size.zero].
///
/// See also:
///
......@@ -207,8 +211,10 @@ class BackdropFilter extends SingleChildRenderObjectWidget {
/// * [Canvas].
class CustomPaint extends SingleChildRenderObjectWidget {
/// Creates a widget that delegates its painting.
CustomPaint({ Key key, this.painter, this.foregroundPainter, Widget child })
: super(key: key, child: child);
CustomPaint({ Key key, this.painter, this.foregroundPainter, this.size: Size.zero, Widget child })
: super(key: key, child: child) {
assert(size != null);
}
/// The painter that paints before the children.
final CustomPainter painter;
......@@ -216,17 +222,28 @@ class CustomPaint extends SingleChildRenderObjectWidget {
/// The painter that paints after the children.
final CustomPainter foregroundPainter;
/// The size that this [CustomPaint] should aim for, given the layout
/// constraints, if there is no child.
///
/// Defaults to [Size.zero].
///
/// If there's a child, this is ignored, and the size of the child is used
/// instead.
final Size size;
@override
RenderCustomPaint createRenderObject(BuildContext context) => new RenderCustomPaint(
painter: painter,
foregroundPainter: foregroundPainter
foregroundPainter: foregroundPainter,
preferredSize: size,
);
@override
void updateRenderObject(BuildContext context, RenderCustomPaint renderObject) {
renderObject
..painter = painter
..foregroundPainter = foregroundPainter;
..foregroundPainter = foregroundPainter
..preferredSize = size;
}
@override
......
......@@ -42,4 +42,39 @@ void main() {
expect(log, equals(<String>['background', 'child', 'foreground']));
});
testWidgets('CustomPaint sizing', (WidgetTester tester) async {
GlobalKey target = new GlobalKey();
await tester.pumpWidget(new Center(
child: new CustomPaint(key: target)
));
expect(target.currentContext.size, Size.zero);
await tester.pumpWidget(new Center(
child: new CustomPaint(key: target, child: new Container())
));
expect(target.currentContext.size, const Size(800.0, 600.0));
await tester.pumpWidget(new Center(
child: new CustomPaint(key: target, size: const Size(20.0, 20.0))
));
expect(target.currentContext.size, const Size(20.0, 20.0));
await tester.pumpWidget(new Center(
child: new CustomPaint(key: target, size: const Size(2000.0, 100.0))
));
expect(target.currentContext.size, const Size(800.0, 100.0));
await tester.pumpWidget(new Center(
child: new CustomPaint(key: target, size: Size.zero, child: new Container())
));
expect(target.currentContext.size, const Size(800.0, 600.0));
await tester.pumpWidget(new Center(
child: new CustomPaint(key: target, child: new Container(height: 0.0, width: 0.0))
));
expect(target.currentContext.size, Size.zero);
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment