pub fn shield<State, V>(child: V) -> ShieldView<State>where
State: 'static,
V: View<State>,Expand description
Platform-view embedding (platform-views feature): reserve
layout space for a native view (a map, a video player, …) composited
alongside the frust surface. platform_view takes the
"dev.frust.<Factory>"-style native factory name registered on each
platform and returns a builder (PlatformViewView) over the
params/size contract — flat-re-exported from frust-widgets so app code
never names that crate directly.
§Paint contract (Mode B)
Under Mode B compositing the frust surface itself is translucent, so any region this slot’s parent doesn’t paint over is a window straight through to the native view (or the OS background) behind it — this is the mechanism Mode B relies on, not a bug. Size/position a slot deliberately, and don’t rely on an unpainted sibling region staying opaque.
Mode B is selected by the generated host’s FRUST_TRANSLUCENT_SURFACE
(Android)/translucentSurface (iOS) build-time constant — not from
Rust: that constant drives, in one host-glue branch, the native window’s
pixel format (PixelFormat.TRANSLUCENT/CAMetalLayer.isOpaque = false),
the native-sibling z-order/subview arrangement, and the
nativeSetSurfaceMode/frust_set_surface_mode call together
(flipping only some of these is a host-template defect). There is
no app-Rust opt-in call; the generated project’s template is
the sole route into Mode B.
use frust::{AnyView, Column, Component, any, platform_view, text};
#[derive(Default)]
struct MapDemo;
impl Component for MapDemo {
type State = ();
fn init(&self) -> Self::State {}
fn build(&self, _state: &mut Self::State) -> AnyView<Self::State> {
any(Column(vec![
any(text("map below")),
any(platform_view("dev.frust.MapFactory")
.params_json(r#"{"style":"dark"}"#)
.size(320.0, 240.0)),
]))
}
}
frust::app!(MapDemo);§Z-shields (shield)
A slot marked .interactive() forwards a touch-DOWN inside its rect to the
native view, including one that landed on frust chrome painted over it (the
OS-side hit test knows nothing about the frust scene). Wrap that chrome in
shield and it keeps winning input: the wrapper reports the rect it
painted every frame, and the shell hands the overlapping ones to the host
with the slot’s placement.
Mark child as frust content that must keep receiving pointer input even
where it paints over an interactive
platform-view slot (the z-shield — see the module docs).
Layout/paint/event/semantics transparent: the child is laid out under the
wrapper’s own constraints at its own size, painted unchanged, and routed
events unchanged. The only added behavior is one
PaintCtx::report_input_shield
call per paint, carrying the rect the wrapper just painted into.
Wrap the narrowest chrome that actually needs input — a shield is a hole in the native view’s input region, so an over-wide one silently takes touches away from it.
any(Stack(vec![
any(platform_view("dev.frust.MapFactory").interactive()),
any(shield(button("recenter", |s: &mut State| s.recenter()))),
]))