Geek Culture
Published in

Geek Culture

Writing custom Widgets in Flutter (Part 3.b) — SimpleOverlay (no helpers)

Intro

Quick Theory

  • Layout — order doesn’t matter unless one child size depends on the size of a different child
  • Paint — back-to-front order when children overlap each other, otherwise order doesn’t really matter
  • HitTest — front-to-back order when children overlap each other, otherwise order doesn’t really matter

Code

class SimpleOverlay extends RenderObjectWidget {
final Widget child;
final Widget overlay;

const SimpleOverlay({
required this.child,
required this.overlay,
});

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

@override
RenderObject createRenderObject(BuildContext context) {
return SimpleOverlayRenderObject();
}
}
class SimpleOverlayElement extends RenderObjectElement {
Element? _child;
Element? _overlay;

// ...

@override
void mount(Element? parent, newSlot) {
super.mount(parent, newSlot);

_child = inflateWidget(widget.child, true);
_overlay = inflateWidget(widget.overlay, false);
}

@override
void update(SimpleOverlay newWidget) {
super.update(newWidget);

_child = updateChild(_child, newWidget.child, true);
_overlay = updateChild(_overlay, newWidget.overlay, false);
}

@override
void unmount() {
super.unmount();

_child = null;
_overlay = null;
}
}
class SimpleOverlayElement extends RenderObjectElement {
// ...

@override
void insertRenderObjectChild(RenderBox child, bool slot) {
renderObject.insertRenderObjectChild(child, slot);
}

@override
void moveRenderObjectChild(RenderBox child, bool oldSlot, bool newSlot) {
renderObject.moveRenderObjectChild(child, oldSlot, newSlot);
}

@override
void removeRenderObjectChild(RenderBox child, bool slot) {
renderObject.removeRenderObjectChild(child, slot);
}
class SimpleOverlayRenderObject extends RenderBox {
//...
RenderBox? _child;
RenderBox? _overlay;

void insertRenderObjectChild(RenderBox child, bool slot) {
if (slot) {
_child = child;
} else {
_overlay = child;
}
adoptChild(child);
}

void moveRenderObjectChild(RenderBox child, bool oldSlot, bool newSlot) {
if (oldSlot) {
_child = null;
} else {
_overlay = null;
}
if (newSlot) {
_child = child;
} else {
_overlay = child;
}
}

void removeRenderObjectChild(RenderBox child, bool slot) {
if (slot) {
_child = null;
} else {
_overlay = null;
}
dropChild(child);
}
}
class SimpleOverlayRenderObject extends RenderBox {
//...

@override
void paint(PaintingContext context, Offset offset) {
if (_child != null) {
context.paintChild(_child!, offset);
}
if (_overlay != null) {
context.paintChild(_overlay!, offset);
}
}

@override
bool hitTestChildren(BoxHitTestResult result, {required Offset position}) {
if (_overlay?.hitTest(result, position: position) == true) {
return true;
}
if (_child?.hitTest(result, position: position) == true) {
return true;
}
return false;
}
}

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