Skip to content

MAUI Phase 5 Slice 1: fix AndroidView fallback sizing for self-drawing views#270

Merged
jonathanpeppers merged 1 commit into
mainfrom
jonathanpeppers/maui-phase-5-graphics
Jun 15, 2026
Merged

MAUI Phase 5 Slice 1: fix AndroidView fallback sizing for self-drawing views#270
jonathanpeppers merged 1 commit into
mainfrom
jonathanpeppers/maui-phase-5-graphics

Conversation

@jonathanpeppers

@jonathanpeppers jonathanpeppers commented Jun 12, 2026

Copy link
Copy Markdown
Owner

On-device verification turned up a real bug, fixed in this slice.

TL;DR

The original commit on this branch claimed every Phase 5 control worked unchanged through ComposeWalker's AndroidView { factory = view.ToPlatform(MauiContext) } fallback — without any device verification. On a Pixel 5, Shapes and GraphicsView paint nothing: their stock Android views (MauiShapeView, PlatformGraphicsView) collapse to 0 × 0 and their Drawable never draws. (Forcing platformView.SetBackgroundColor(Color.Magenta) was invisible — proved zero size, not zero paint.)

Root cause: the fallback never applied a Compose Modifier.Size derived from MAUI's WidthRequest / HeightRequest. Compose handed AndroidView an unbounded slot. Compose-native handlers like BoxViewHandler already did this themselves; the fallback was the only path missing it.

Fix is one switch expression in ComposeWalker.Render. No new handlers, no new public surface.

Per-control verdict (on-device, Pixel 5)

Control Verdict
Shapes (Rectangle / RoundRectangle / Ellipse / Line / Polygon / Polyline / Path) Works via fallback after the fix. All 7 shape kinds + fill-width Rectangle render.
GraphicsView (IDrawable) Works via fallback after the fix. Invalidate() repaints — tap-to-reshuffle bumps the seed and the canvas redraws.
WebView Works via fallback (handler shape implies parity; sample page deleted — added no Compose-specific value).
HybridWebView Deferred. Same handler shape as WebView, expected to work — not part of this slice's verification matrix.
BlazorWebView Works via fallback by construction (ViewHandler over Android WebView); not exercised to avoid the package dependency.
Grid / AbsoluteLayout / FlexLayout / StackLayout Works via fallback. Already shipping unmodified on HomePage.xaml's Grid chrome since Phase 1. Sample page deleted.

Sample page changes

Kept (on-device reproducers for the bug):

  • Pages/ShapesPage.xaml(.cs)
  • Pages/GraphicsViewPage.xaml(.cs)

Deleted (the controls work via the fallback after the fix and the demos surfaced no Compose-specific behaviour worth a gallery slot):

  • Pages/WebViewPage.xaml(.cs)
  • Pages/HybridWebViewPage.xaml(.cs) + Resources/Raw/hybridroot/index.html
  • Pages/LayoutsPage.xaml(.cs)

Out of scope

Verification

  • dotnet test src/Microsoft.AndroidX.Compose.SourceGenerators.Tests = 155 passed.
  • dotnet build src/Microsoft.AndroidX.Compose clean.
  • dotnet build src/Microsoft.AndroidX.Compose.Maui clean.
  • dotnet build src/Microsoft.AndroidX.Compose.Maui.Sample clean (zero warnings, zero errors).
  • dotnet build src/Microsoft.AndroidX.Compose.Maui.Sample -t:Install clean.
  • dotnet build src/Microsoft.AndroidX.Compose.Gallery clean.
  • On-device on a Pixel 5: deployed, exercised both kept sample pages — Shapes and GraphicsView render and respond as designed.

Copilot AI review requested due to automatic review settings June 12, 2026 22:28

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR closes Phase 5 Slice 1 by adding investigation-only sample pages that verify various MAUI controls (Shapes, GraphicsView, WebView, HybridWebView, and unsupported layouts) render correctly through the existing AndroidView fallback path in ComposeWalker. No new Compose-backed handlers or library code changes are introduced — the PR demonstrates that the stock MAUI handlers work as-is when hosted inside a Compose composition via AndroidView interop.

Changes:

  • Five new sample pages (ShapesPage, GraphicsViewPage, WebViewPage, HybridWebViewPage, LayoutsPage) with XAML + code-behind exercising every Phase 5 control through unmodified stock handlers.
  • Shell route registrations and HomePage catalog entries wiring the new pages into the sample app, plus a hybridroot/index.html raw asset for the HybridWebView JS bridge round-trip demo.
  • docs/maui-backend.md updated with a comprehensive Phase 5 Slice 1 subsection: per-control verdict matrix, verification gap disclosure, intentional exclusions, and follow-up tracking.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
Pages/ShapesPage.xaml(.cs) New XAML page exercising all seven Shapes subclasses via the stock ShapeViewHandler fallback.
Pages/GraphicsViewPage.xaml(.cs) New page with a synthetic IDrawable sparkline + tap-to-reshuffle, verifying GraphicsViewHandler fallback + Invalidate().
Pages/WebViewPage.xaml(.cs) New page with HtmlWebViewSource inline JS counter + about:blank URL baseline.
Pages/HybridWebViewPage.xaml(.cs) New page verifying HybridWebView JS bridge round-trip (SendRawMessage/RawMessageReceived).
Pages/LayoutsPage.xaml(.cs) New page hosting Grid, AbsoluteLayout, FlexLayout via the AndroidView fallback.
Resources/Raw/hybridroot/index.html Minimal HTML + JS for the HybridWebView bridge demo.
AppShell.xaml.cs Shell route registrations for the five new pages.
HomePage.xaml.cs Catalog entries for the five new demos.
docs/maui-backend.md Replaces brief Phase 5 stub with full investigation report, per-control matrix, and follow-up plan.

Comment thread src/Microsoft.AndroidX.Compose.Maui.Sample/Pages/HybridWebViewPage.xaml Outdated
Comment thread src/Microsoft.AndroidX.Compose.Maui.Sample/AppShell.xaml.cs Outdated
…g views

The original commit on this branch claimed every Phase 5 control worked
unchanged through `ComposeWalker`'s `AndroidView { factory =
view.ToPlatform(MauiContext) }` fallback. On-device verification on a
Pixel 5 proved that wrong for self-drawing views: `MauiShapeView` and
`PlatformGraphicsView` painted nothing - even forcing
`platformView.SetBackgroundColor(Color.Magenta)` was invisible, which
proves the View was getting a 0 x 0 layout slot.

Root cause: the fallback never applied a Compose `Modifier.Size` (or
`.Width`/`.Height`) derived from MAUI's `WidthRequest`/`HeightRequest`.
Compose handed `AndroidView` an unbounded slot, the embedded View
measured wrap-content, and self-drawing Views with no intrinsic size
collapsed and their `Drawable` painted nothing. Compose-native handlers
like `BoxViewHandler` already did this themselves via
`IComposeHandler.BuildNode`; the fallback was missing the same mapping.

Fix sits inside `ComposeWalker.Render`: read `WidthRequest`/`HeightRequest`
off the `Microsoft.Maui.Controls.VisualElement` and translate to
`Modifier.Size` / `Modifier.Width` / `Modifier.FillMaxWidth().Height(...)`,
matching `BoxViewHandler`. No new public surface, no new handler.

Sample pages reduced to the two with Compose-specific behaviour worth
keeping as on-device reproducers for the bug:

* `Pages/ShapesPage.xaml(.cs)` - all seven shape kinds
  (Rectangle / RoundRectangle / Ellipse / Line / Polygon / Polyline /
  Path) plus a fill-width Rectangle that exercises the
  `WidthRequest = -1, HeightRequest >= 0` branch.
* `Pages/GraphicsViewPage.xaml(.cs)` - `IDrawable` paints a random
  zigzag plot; tap-to-reshuffle bumps the seed and `Invalidate()`s.

The other three pages from the original slice (`WebViewPage`,
`HybridWebViewPage`, `LayoutsPage`) are deleted - they exercised
controls that already work via fallback (or already ship in working
form across other sample pages, in the case of `Grid` /
`AbsoluteLayout` / `FlexLayout` on `HomePage.xaml`) and didn't surface
new Compose-specific behaviour worth the gallery slot.

`docs/maui-backend.md` Phase 5 section rewritten to reflect the truth:
per-control matrix updated (every shape + GraphicsView marked "works
via fallback after the size-modifier fix"), `HybridWebView` moved to
"deferred", verification matrix replaced with a concrete on-device
verdict on a Pixel 5.

Verified:

* `dotnet test src/Microsoft.AndroidX.Compose.SourceGenerators.Tests`
  = 155 passed.
* `dotnet build src/Microsoft.AndroidX.Compose` clean.
* `dotnet build src/Microsoft.AndroidX.Compose.Maui` clean.
* `dotnet build src/Microsoft.AndroidX.Compose.Maui.Sample` clean.
* `dotnet build src/Microsoft.AndroidX.Compose.Maui.Sample -t:Install`
  clean.
* `dotnet build src/Microsoft.AndroidX.Compose.Gallery` clean.
* On-device on a Pixel 5: deployed, navigated to Shapes (all seven
  shape kinds + fill-width Rectangle render correctly) and to
  GraphicsView (canvas paints, tap-to-reshuffle redraws the plot and
  bumps the seed badge from 0 to 1).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers jonathanpeppers force-pushed the jonathanpeppers/maui-phase-5-graphics branch from 816b24d to 1607f14 Compare June 15, 2026 15:43
@jonathanpeppers jonathanpeppers changed the title MAUI Phase 5 Slice 1: AndroidView fallback investigation MAUI Phase 5 Slice 1: fix AndroidView fallback sizing for self-drawing views Jun 15, 2026
@jonathanpeppers jonathanpeppers enabled auto-merge (squash) June 15, 2026 15:49
@jonathanpeppers jonathanpeppers merged commit 770f49b into main Jun 15, 2026
1 check passed
@jonathanpeppers jonathanpeppers deleted the jonathanpeppers/maui-phase-5-graphics branch June 15, 2026 15:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants