Writing custom Widgets in Flutter (Part 2.b) — ChildSize (no helpers)

Into

Code

class ChildSize extends RenderObjectWidget {
// ...
final Widget? child;
const ChildSize({
Key? key,
this.child,
this.onChildSizeChanged,
}) : super(key: key);

@override
RenderObjectElement createElement() {
return ChildSizeElement(this);
}

// ...
}
class ChildSizeElement extends RenderObjectElement {
ChildSizeElement(ChildSize widget) : super(widget);

@override
ChildSize get widget {
return super.widget as ChildSize;
}

@override
RenderChildSize get renderObject {
return super.renderObject as RenderChildSize;
}
}
class ChildSizeElement extends RenderObjectElement {
// ...
Element? _child;

@override
void mount(Element? parent, Object? newSlot) {
super.mount(parent, newSlot);
_child = updateChild(_child, widget.child, null);
}

@override
void update(ChildSize newWidget) {
super.update(newWidget);
_child = updateChild(_child, newWidget.child, null);
}

@override
void unmount() {
super.unmount();
_child = null;
}
}
  • mount — called when our Element is created and attached to its parent. Here we need to inflate all our children elements. In our case we have only one child.
  • update — called when our Widget has changed. This might also change our child, so we need to update it as well.
  • unmount — this is the final callback, at this point Element is destroyed. Now we can release the reference to our child.
  • First argument is a previous version of our child Element. If there is no Element available — null can be passed.
  • Second argument — new Widget for the child Element. Based on this Widget it will decide whether to reuse previous Element, or to delete it and create a new one.
  • Third argument is a slot. Slots are kind of interesting and can be anything — id, index, some other characteristic. The main point of slots is to identify child Element’s position. Because we have only one child — null can be passed.
class ChildSizeElement extends RenderObjectElement {
// ...

@override
void visitChildren(ElementVisitor visitor) {
final child = _child;
if (child != null) {
visitor(child);
}
super.visitChildren(visitor);
}

@override
void forgetChild(Element child) {
assert(child == _child);
_child = null;
super.forgetChild(child);
}
}
class ChildSizeElement extends RenderObjectElement {
// ...

@override
void insertRenderObjectChild(RenderBox child, covariant Object? slot) {
renderObject.insertRenderObjectChild(child, slot);
}

@override
void removeRenderObjectChild(RenderBox child, covariant Object? slot) {
renderObject.removeRenderObjectChild(child, slot);
}
}
class RenderChildSize extends RenderBox {
RenderBox? _child;

@override
void attach(covariant PipelineOwner owner) {
super.attach(owner);
_child?.attach(owner);
}

@override
void detach() {
super.detach();
_child?.detach();
}

@override
void visitChildren(RenderObjectVisitor visitor) {
final child = _child;
if (child != null) {
visitor(child);
}
super.visitChildren(visitor);
}

@override
void redepthChildren() {
final child = _child;
if (child != null) {
redepthChild(child);
}
super.redepthChildren();
}
}
class RenderChildSize extends RenderBox {
// ...

void insertRenderObjectChild(RenderBox child, covariant Object? slot) {
assert(_child == null);
_child = child;
adoptChild(child);
}

void removeRenderObjectChild(RenderBox child, covariant Object? slot) {
assert(_child == child);
_child = null;
dropChild(child);
}
}

Other articles:

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store