I'm writing an overlay package for flutter for tutorial walk-through.
In order to know which holes to make in the overlay to make the widgets behind it fully visible, the function requires a list of global keys and I use them to fetch location and size.
While the overlay is still visible, the widgets can be animated and move to a different location. Is there a way to detect that in order to re-draw the overlay?
I know that if I add a mixin of WidgetsBindingObserver to the widgets, I can check that with didChangeMetrics()
. The problem is that I don't want the user to modify is original code. Is there a way to observe widgets metrics without changing their code?
My code is at https://github.com/kfirufk/tuxin_tutorial_overlay
so thanks to @pskink amazing support I was able to properly resolve this issue.
I already have the Global Keys of the widgets I want to monitor for changes in size and position, so I don't need to drill down through all the widgets in the app.
so I'm adding a persistent frame callback and in there I check that that overlay being shown actually have holes to show widgets behind it, and if it doesת I use the _sizeVisitor()
function to detect if any of the widgets position or size where modified, and if they where, I redraw the widget.
again.. thank you so much @pskink!
void _detectWidgetPositionNSizeChange() {
var bindings = WidgetsFlutterBinding.ensureInitialized();
bindings.addPersistentFrameCallback((d) {
if (visibleOverlayPage != null &&
(visibleOverlayPage.disabledVisibleWidgetsCount +
visibleOverlayPage.enabledVisibleWidgetsCount >
0)) {
for (final widgetGlobalKey in visibleOverlayPage.widgetsGlobalKeys) {
if (_sizeVisitor(widgetGlobalKey)) {
redrawCurrentOverlay();
break;
}
}
}
});
}
bool _sizeVisitor(GlobalKey elementKey) {
if (elementKey.currentContext != null) {
final RenderBox renderBox = elementKey.currentContext.findRenderObject();
bool isChanged = false;
Rect newRect = renderBox.localToGlobal(Offset.zero) & renderBox.size;
_rectMap.update(elementKey, (oldRect) {
if (newRect != oldRect) {
isChanged = true;
}
return newRect;
}, ifAbsent: () => newRect);
return isChanged;
} else {
return false;
}
}