Skip to content

Render SwiftUI view modifiers on Android#9

Merged
colemancda merged 11 commits into
masterfrom
feature/modifiers
Jul 22, 2026
Merged

Render SwiftUI view modifiers on Android#9
colemancda merged 11 commits into
masterfrom
feature/modifiers

Conversation

@colemancda

Copy link
Copy Markdown
Member

Summary

View modifiers previously had no effect on Android. ModifiedContent's AndroidPrimitive conformance was incomplete — it unconditionally flattened to the unmodified content, silently discarding every modifier. Only .opacity() worked, via a separate self-contained mechanism that never went through this path.

This wires up a real dispatcher and adds per-modifier conformances for the core layout and effect modifiers.

What's included

  • ModifiedContent dispatcher — applies AndroidViewModifier conformances imperatively to the resolved native view, and reproduces the view-tree expansion for the background/overlay modifiers that genuinely build a distinct tree.
  • AndroidCompositingContainer — a self-mounting FrameLayout host backing .background()/.overlay(). It creates and attaches children imperatively rather than via ParentView/reconciler diffing, because it's frequently reached through an outer modifier's own resolution path, which bypasses the reconciler entirely. Built to be reused for ZStack.
  • Color as a native viewColor had no direct renderer (its Body was a shape-view composite with no native backing), so it couldn't be used as bare content for compositing.
  • Modifier conformances.padding(), .frame(), .offset(), .rotationEffect(), .scaleEffect(), .clipShape()/.cornerRadius().
  • Gallery screenModifierScreen exercising each modifier individually.

Notes

  • .background(Color.x) resolves to _BackgroundStyleModifier, not _BackgroundModifier — Swift picks the more specific ShapeStyle-constrained overload since Color conforms to both. Only solid Color styles render; gradients and materials need a Shape-backed renderer that doesn't exist yet, so they're skipped rather than rendered wrong.
  • Clip handles rounded-rect and plain-rect only, the dominant real-world usage.
  • .foregroundColor is not included — it has no dedicated modifier struct upstream and needs an environment-read hook in AndroidText instead.

Verification

All seven sections of the new gallery screen confirmed rendering correctly on the emulator: padding, frame, background, clip + corner radius, offset, rotation, and scale.

Previously ModifiedContent's AndroidPrimitive conformance was incomplete: it
unconditionally flattened to the unmodified content, silently discarding any
modifier's effect. Wire up a proper dispatcher that applies AndroidViewModifier
conformances imperatively and reproduces the view-tree expansion of the
background/overlay modifiers that actually build a distinct view tree.
…yout

Adds AndroidCompositingContainer, a self-mounting FrameLayout host that creates
and attaches its children's native views imperatively rather than exposing
them through ParentView/reconciler diffing — necessary because this container
is often reached via an outer view modifier's own resolution path, which
bypasses the reconciler entirely.
Color previously had no direct Android renderer (its Body was a shape-view
composite with no native backing), so it couldn't be used as bare content —
needed for compositing it behind/over other views for backgrounds/overlays.
Only rounded-rect and plain-rect shapes are handled — the by-far dominant
real-world usage — via a GradientDrawable outline and setClipToOutline.
@colemancda
colemancda merged commit f217b2c into master Jul 22, 2026
6 checks passed
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.

1 participant