feat(mapview): add staticMode prop for static maps in lists#85
Merged
Conversation
drawMapRect: runs on MapKit's background render queues; snapshot polyline/distances/colors so main-thread updates can't cause out-of-bounds reads or use-after-free of the color cache
- reset static content on staticKey change (prevents stale/poisoned snapshot cache with in-place list recycling) - re-arm snapshot swap on zero-size capture instead of giving up - bound snapshot cache by memory; include camera in cache key - reset recycled wrapper placeholder styling - web: disable POI clicks, keyboard, and press handlers in staticMode
No live MKMapView is created - the base map renders off the main thread and keeps loading while scrolling, like Android lite mode. Markers are live views positioned via mercator projection; shapes are drawn onto a CoreGraphics overlay. Removes the old snapshot-swap path from AppleMapProvider (now Google-only via the warmup queue).
Creating and tearing down a GMSMapView are expensive main-thread operations; detached static maps are pooled (capacity 3, keyed by map ID) and reused, so a warmup usually only costs a camera move plus tile load. Pool drains on memory warnings.
…ase warmup Extract Apple static provider's overlay machinery (projection, live marker views, CG shape overlay) into StaticMapProviderBase and add GoogleStaticMapProvider: markers/shapes show immediately without a warmup slot; only the base map warms up on a pooled, tiles-only GMSMapView below the overlays, then swaps to an image. Strips static mode from GoogleMapProvider and warmup bookkeeping from LuggMapView.
Live (non-rasterized) markers were positioned with a garbage projection before the lite map rendered, flashing off-position until onMapLoaded corrected them. Keep them invisible until positioned correctly.
Markers and shapes no longer show over the placeholder while the base map loads; they stay hidden and appear together with it, matching Android lite mode.
Google static maps now warm up as soon as rows mount instead of queuing behind a 3-slot, scroll-gated warmup queue. Apps bound concurrent work via list props (windowSize etc.).
The swap is deferred while scrolling, so markers stayed hidden over an already-rendered warmup map. Decouple the overlay reveal from the swap.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a
staticModeprop toMapViewfor rendering non-interactive static maps, optimized for list views where mounting many live maps is expensive, plus astaticKeyprop for snapshot caching across list recycling.GoogleMapOptions.liteMode), rendering a static bitmap instead of a live GL surface.mapIdis skipped (unsupported in lite mode), the lite toolbar is disabled, and live (non-rasterized) markers stay hidden until the map has loaded so they never flash at an invalid projection.StaticMapProviderBase: markers are live overlay views positioned via a mercator projection (async content like remote images still updates), polylines/polygons/circles/ground overlays draw into a single CoreGraphics overlay, and all overlays stay hidden over a theme-aware placeholder until the base map displays.MKMapSnapshotter, entirely off the main thread; no live map view is ever created.GMSMapViewunder the overlays, then swaps to a rendered image (swap deferred outside scroll tracking). Warmup map views are pooled and reused; overlays reveal as soon as tiles finish rendering. Warmup concurrency is unbounded - apps control it via list props (windowSize, etc.).staticKeycaches base-only snapshot images (boundedNSCache) keyed by camera, size, provider, and map settings; markers/shapes always re-render live from props.animatedpolylines render as complete static polylines.gestureHandling: 'none'.staticModeis creation-time only. On iOS, camera commands and prop updates are no-ops after the base map renders.Example: new
StaticMapsScreen(shared) renders a 100-row FlatList of pressable place cards cycling marker use-cases (default, icon, text, remote image, multiple) plus a per-card constellation polyline with dot markers, with an Apple/Google provider toggle. Wired into bare (StaticMapsroute) and expo (/static-maps).Type of Change
Test Plan
yarn typecheck,yarn test,yarn lint, ktlint, objclint passstaticKeycache reuseScreenshots / Videos
N/A
Checklist