build method

  1. @override
Widget build(
  1. BuildContext context
)
override

Builds the widget subtree for this state.

Implementation

@override
Widget build(BuildContext context) {
  // Collect all overlay entries from all routes.
  final entries = <OverlayEntry>[];
  for (final route in _routes) {
    entries.addAll(route.overlayEntries);
  }

  if (entries.isEmpty) {
    return SizedBox.shrink();
  }

  // Find the lowest opaque entry — everything from there upward is visible.
  var opaqueIndex = 0;
  for (var i = entries.length - 1; i >= 0; i--) {
    if (entries[i].opaque) {
      opaqueIndex = i;
      break;
    }
  }

  // Build children list using _RouteEntry wrappers with stable keys.
  // Offstage entries come first and active entries come last.
  // Element.dispatch walks children in reverse order for KeyMsg (one-winner
  // policy), so placing active entries last ensures they receive keyboard
  // input before offstage entries.
  // Offstage entries render as zero-size (SizedBox 0x0) and their
  // handleIntercept returns Cmd.none() to suppress message delivery to
  // their children.
  //
  // Using a single _RouteEntry type with a stable Key for each entry
  // ensures Widget.canUpdate returns true when an entry transitions
  // between active↔offstage (same runtimeType + same Key). The
  // _RouteEntry.build() always returns SizedBox(child: widget.child)
  // keeping the subtree structure identical and preserving child
  // State objects and pending Futures.
  final children = <Widget>[];

  // Offstage entries first (below opaqueIndex, maintainState only).
  for (var i = 0; i < opaqueIndex; i++) {
    if (entries[i].maintainState) {
      final key = _entryKeys[entries[i]];
      children.add(
        _RouteEntry(
          key: key,
          offstage: true,
          child: entries[i].builder(context),
        ),
      );
    }
  }

  // Active entries last (from opaqueIndex onward).
  for (var i = opaqueIndex; i < entries.length; i++) {
    final key = _entryKeys[entries[i]];
    children.add(_RouteEntry(key: key, child: entries[i].builder(context)));
  }

  // Always use a Stack — even for a single child — so the element tree
  // structure remains stable across push/pop cycles and State objects
  // are preserved rather than disposed and re-created.
  final result = Stack(fit: StackFit.expand, children: children);

  // Wrap in FocusScope to trap focus in the navigator.
  return FocusScope(isTrapped: true, child: result);
}