BoxyDelegate<LayoutData extends Object> class
abstract
A delegate that controls the layout and paint of child widgets, used by CustomBoxy.
Delegates must ensure an identical delegate would produce the same layout. If your delegate takes arguments also make sure shouldRelayout and/or shouldRepaint return true when those fields change.
A single delegate can be used by multiple widgets at a time and should not keep any state. If you need to pass information from layout to another method, store it in layoutData or BoxyChild.parentData.
Delegates may access their children by name with getChild, alternatively they can be accessed through the children list.
The default constructor accepts Listenables that can trigger re-layout and re-paint. It's much more efficient for the boxy to listen directly to animations than rebuilding the CustomBoxy with a new delegate each frame.
Layout
Override layout to control the layout of children and return what size the boxy should be.
This method should call BoxyChild.layout for each child. It should also specify the position of each child with BoxyChild.position.
If the delegate does not depend on the size of a particular child, pass
useSize: false
to BoxyChild.layout, this prevents a change in the
child's size from causing a re-layout.
The following example lays out two children like a column where the second widget is the same width as the first:
@override
Size layout() {
// Get both children by a Symbol id
var firstChild = getChild(#first);
var secondChild = getChild(#second);
// Lay out the first child with the incoming constraints
var firstSize = firstChild.layout(constraints);
firstChild.position(Offset.zero);
// Lay out the second child
var secondSize = secondChild.layout(
constraints.deflate(
// Subtract height consumed by the first child from the constraints
EdgeInsets.only(top: firstSize.height),
).tighten(
// Force width to be the same as the first child
width: firstSize.width,
)
);
// Position the second child below the first
secondChild.position(Offset(0, firstSize.height));
// Calculate the total size based both child sizes
return Size(
firstSize.width,
firstSize.height + secondSize.height,
);
}
Painting
Override paint to draw behind children, this is similar to CustomPainter.paint which gives you a Canvas.
The following example simply gives the widget a blue background:
@override
void paint() {
canvas.drawRect(
Offset.zero & renderSize,
Paint()..color = Colors.blue,
);
}
You can draw above children similarly by overriding paintForeground.
Override paintChildren to change how children themselves are painted, for example changing the order or adding layers.
The default behavior is to paint children at the BoxyChild.offset given to them during layout.
The canvas available to paintChildren is not transformed implicitly like paint and paintForeground, implementers of this method should draw at paintOffset and restore the canvas before painting a child. This is required by the framework because a child might need to insert its own compositing Layer between two other PictureLayers.
The following example draws a semi transparent rectangle between two children:
@override
void paintChildren() {
getChild(#first).paint();
canvas.drawRect(
paintOffset & render.size,
Paint()..color = Colors.blue.withOpacity(0.3),
);
getChild(#second).paint();
}
Layers
In order to apply special effects to children such as transforms, opacity, clipping, etc. delegates will need to interact with the compositing tree. Boxy wraps this functionality conveniently with layers.
Before a delegate can push layers make sure to override needsCompositing. This getter can check the fields of the boxy to determine if compositing will be necessary, return true if that is the case.
The following example paints its child with 50% opacity:
@override
bool get needsCompositing => true;
@override
void paintChildren() {
layers.opacity(
opacity: 0.5,
paint: () {
getChild(#first).paint();
},
);
}
Widget inflation
One of the most powerful features of the boxy library is to inflate arbitrary widgets at layout time, this would otherwise be extraordinarily difficult to implement in Flutter.
In layout delegates can inflate arbitrary widgets using the inflate method, this enables complex layouts where the contents of widgets change depending on the size and orientation of others, in addition to constraints.
After calling this method the child becomes available in children and any following painting and hit testing, it is removed from the list before the next layout.
Unlike children explicitly passed to CustomBoxy, Keys are not managed for widgets inflated during layout, this means a widgets state is preserved if inflated again with the same object id, rather than equal Keys.
The following example displays a text widget describing the size of another child:
@override
Size layout() {
var firstChild = getChild(#first);
var firstSize = firstChild.layout(constraints);
firstChild.position(Offset.zero);
var text = Padding(child: Text(
"^ This guy is ${firstSize.width} x ${firstSize.height}",
textAlign: TextAlign.center,
), padding: EdgeInsets.all(8));
// Inflate the text widget
var secondChild = inflate(text, id: #second);
var secondSize = secondChild.layout(
constraints.deflate(
EdgeInsets.only(top: firstSize.height)
).tighten(
width: firstSize.width
)
);
secondChild.position(Offset(0, firstSize.height));
return Size(
firstSize.width,
firstSize.height + secondSize.height,
);
}
See also:
- CustomBoxy, the widget of a boxy.
- BoxyChild, a child handle for RenderBox.
- SliverBoxyChild, a child handle for RenderSliver.
- BoxyLayerContext, a wrapper that can push Layers.
- BoxBoxyDelegate, a base delegate that supports both BoxyChild and SliverBoxyChild.
- Inheritance
-
- Object
- BaseBoxyDelegate<
LayoutData, BoxyChild> - BoxyDelegate
- Mixed in types
-
- BoxBoxyDelegateMixin<
LayoutData, BoxyChild>
- BoxBoxyDelegateMixin<
Constructors
- BoxyDelegate({Listenable? relayout, Listenable? repaint})
-
Constructs a BoxyDelegate with optional
relayout
andrepaint
Listenables.
Properties
- buildContext → BuildContext
-
Gets the BuildContext of this boxy.
no setterinherited
- canvas → Canvas
-
The current canvas, should only be accessed from paint methods.
no setterinherited
-
children
→ List<
BoxyChild> -
A list of each
BoxyChild
handle associated with the boxy, the list itself should not be modified by the delegate.no setterinherited - constraints → BoxConstraints
-
The most recent constraints given to this boxy by its parent.
no setterinherited
- debugPhase → BoxyDelegatePhase
-
The current phase in the render pipeline that this boxy is performing,
only valid in debug mode.
no setterinherited
- hashCode → int
-
The hash code for this object.
no setterinherited
- hitTestResult → BoxHitTestResult
-
The current hit test result, should only be accessed from hitTest.
no setterinherited
- indexedChildCount → int
-
The number of children that have not been given a BoxyId, this
guarantees there are child ids between 0 (inclusive) and indexedChildCount
(exclusive).
no setterinherited
- isDryLayout → bool
-
Whether or not this boxy is performing a dry layout.
no setterinherited
- layers → BoxyLayerContext
-
The current layer context, useful for pushing Layers to the scene during
paintChildren.
no setterinherited
- layoutData ↔ LayoutData?
-
A variable to hold additional data created during layout which can be
used while painting and hit testing.
getter/setter pairinherited
- needsCompositing → bool
-
Override this method to return true if the paint method will push one or
more layers to paintingContext.
no setterinherited
- paintingContext → PaintingContext
-
The current painting context, should only be accessed from paint methods.
no setterinherited
- paintOffset → Offset
-
The offset of the current paint context.
no setterinherited
-
render
→ RenderBoxy<
BoxyChild> -
The RenderBoxyMixin of the current context.
no setterinherited
- renderSize → Size
-
The last size returned by layout.
no setterinherited
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
Methods
-
addHit(
) → void -
Adds the boxy to hitTestResult, this should typically be called from
hitTest when a hit succeeds.
inherited
-
distanceToBaseline(
TextBaseline baseline) → double? -
Override to return the distance from the y-coordinate of the position of
the box to the y-coordinate of the first given baseline in the box's
contents, if any, or null otherwise.
inherited
-
getChild<
T extends ChildHandleType> (Object id) → T -
Gets the child handle with the specified
id
.inherited -
getChildOrNull<
T extends ChildHandleType> (Object id) → T? -
Gets the child handle with the specified
id
or returns null if there is no child with givenid
.inherited -
hasChild(
Object id) → bool -
Returns true if a child exists with the specified
id
.inherited -
hitTest(
SliverOffset position) → bool -
Override this method to change how the boxy gets hit tested.
inherited
-
inflate<
T extends ChildHandleType> (Widget widget, {Object? id}) → T -
Dynamically inflates a widget as a child of this boxy, should only be
called in BoxyChild.layout.
inherited
-
layout(
) → Size -
Override this method to lay out children and return the final size of the
boxy.
override
-
maxIntrinsicHeight(
double width) → double -
Override to change the maximum height that this box could be without
failing to correctly paint its contents within itself, without clipping.
inherited
-
maxIntrinsicWidth(
double height) → double -
Override to change the maximum width that this box could be without
failing to correctly paint its contents within itself, without clipping.
inherited
-
minIntrinsicHeight(
double width) → double -
Override to change the minimum height that this box could be without
failing to correctly paint its contents within itself, without clipping.
inherited
-
minIntrinsicWidth(
double height) → double -
Override to change the minimum width that this box could be without
failing to correctly paint its contents within itself, without clipping.
inherited
-
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
onPointerEvent(
PointerEvent event, covariant BoxHitTestEntry entry) → void -
Override to handle pointer events that hit this boxy.
inherited
-
paint(
) → void -
Override this method to paint below children.
inherited
-
paintChildren(
) → void -
Override this method to change how children get painted.
inherited
-
paintForeground(
) → void -
Override this method to paint above children.
inherited
-
paintLayer(
ContainerLayer layer, {VoidCallback? painter, Offset? offset, Rect? debugBounds}) → void -
Paints a ContainerLayer compositing layer in the current painting
context with an optional
painter
callback, this should only be called in paintChildren.inherited -
shouldRelayout(
covariant BaseBoxyDelegate< Object, BaseBoxyChild> oldDelegate) → bool -
Override this method to return true when the children need to be
laid out.
inherited
-
shouldRepaint(
covariant BaseBoxyDelegate< Object, BaseBoxyChild> oldDelegate) → bool -
Override this method to return true when the children need to be
repainted.
inherited
-
toString(
) → String -
Override this method to include additional information in the
debugging data printed by debugDumpRenderTree and friends.
inherited
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited