show static method
Future<void>
show({
- required BuildContext context,
- required BubbleLabelContent bubbleContent,
- bool animate = true,
- GlobalKey<
State< ? anchorKey,StatefulWidget> >
Show a bubble overlay with the provided bubbleContent.
If animate is true (default) the opening animation will be
played. If another bubble is active, it is dismissed first and
then the new one is shown.
context is required and serves two purposes:
- Finding the Overlay widget in the widget tree
- As the anchor widget for positioning (if no
anchorKeyorpositionOverrideis provided)
anchorKey is optional. If provided, the bubble will be anchored to
that widget. If not provided and no positionOverride is set, the
bubble will be anchored to the widget associated with context.
Requires: An Overlay widget in the widget tree (provided by MaterialApp, CupertinoApp, or manually added).
Implementation
static Future<void> show({
required BuildContext context,
required BubbleLabelContent bubbleContent,
bool animate = true,
GlobalKey? anchorKey,
}) async {
var content = bubbleContent;
// Use the provided context for overlay lookup
final targetContext = context;
// Try root overlay first (works in most cases with MaterialApp/CupertinoApp)
OverlayState? overlay = Overlay.maybeOf(targetContext, rootOverlay: true);
// Fallback to nearest overlay
overlay ??= Overlay.maybeOf(targetContext, rootOverlay: false);
if (overlay == null) {
_throwOverlayError();
return;
}
// Resolve render box BEFORE any async gaps to avoid lint warning
// "Don't use BuildContext across async gaps"
RenderBox? renderBox;
if (anchorKey != null) {
renderBox = _resolveAnchorRenderBox(anchorKey);
} else if (content.positionOverride == null) {
// Use the context's render object as the anchor
final renderObject = context.findRenderObject();
if (renderObject is RenderBox) {
renderBox = renderObject;
}
}
// Capture the Overlay's RenderBox for coordinate conversion.
// This is needed to properly position bubbles when ancestor widgets
// contain transforms (e.g., ForcePhoneSizeOnWeb, Transform.scale).
RenderBox? overlayRenderBox;
final overlayContext = overlay.context;
final overlayRenderObject = overlayContext.findRenderObject();
if (overlayRenderObject is RenderBox) {
overlayRenderBox = overlayRenderObject;
}
//dismiss the previous bubble (just in case)
if (BubbleLabel.isActive) {
// When replacing an active bubble, honor the caller's animate flag.
await BubbleLabel.dismiss(animate: animate);
}
// Set the overlayRenderBox AFTER dismiss to avoid it being cleared
// when replacing an active bubble with a new one.
_bubbleLabelOverlayRenderBoxController.state = overlayRenderBox;
if (animate) {
BubbleLabel._animationController.state = true;
}
if (renderBox != null && renderBox != content._renderBox) {
content = content._withRenderBox(renderBox);
}
// Store the anchor key for dynamic position tracking (null if using context)
_activeAnchorKey = anchorKey;
//set the new bubble content
BubbleLabel.controller.update<BubbleLabelContent?>((state) => content);
// Insert entries using the pre-resolved overlay
_insertOverlayEntries(content, overlay);
}