Unified rendering buys visual consistency at the cost of system behavior
Aliases: custom renderer · Flutter canvas · self-drawn UI
What it is
Flutter, game engines, and many self-drawn UI frameworks paint pixels with their own renderer on each side, so a button can look identical on iOS and Android. What is bought is still-frame sameness across ends. What is paid is the behavior the system used to host: scroll physics, text-selection handles, the share sheet, the back gesture, overscroll, the dictation insertion point. Call the swap a renderer-for-behavior tradeoff. Visual sameness is not a side effect of a brand decision. It is a direct consequence of the rendering architecture.
This is not the same mechanism as “unifying look across platforms violates both sides’ conventions.” That leaf is about which side a brand chooses to stand on. This leaf is: once pixels come from your own canvas, the system behavior substrate is gone by default. To have the behavior you reimplement it, or you do not have it.
Why it happens
System controls are where behavior lives. Inertial curves, the magnifier on a selection, the handshake between field and keyboard — they hitch to system objects. A self-drawn control is a picture that handles touches and does not hitch to those hosts. A framework can mimic some of them — its own scrolling, its own caret — but mimicry is a whitelist: anything not rebuilt disappears. When the OS upgrades, system apps follow; the self-drawn app stays at the last version the framework implemented.
Sameness is cheap precisely because the substrate was dropped. Drop it once per side, and the two sides look more alike. The cost shows on the first gesture that arrives as system muscle memory: the selection menu that should appear does not, the inertia is wrong, a gesture the system should own is eaten by the canvas.
Where it stops holding
A product that ships on one side, or that is explicitly a game-like full-screen canvas, does not arrive with system muscle memory; the sting of the swap is low. Embedding a few system controls as platform views can redeem local behavior, though the seam itself cracks again on scroll and focus. The web is already a self-drawn layer inside the browser; the cost structure is similar, with the browser as substrate instead of UIKit. Surfaces that are display-only, with no editing and no system share, lose a shorter behavior list; the swap may be worth it.
Applying it
- When choosing a self-drawn framework, list the system behaviors that must remain (selection, scroll physics, share, back, input) and mark each as provided, mimicked, or missing.
- Prefer embedding platform views for editing, system share, payment, and permission surfaces that must feel like the system, rather than drawing everything.
- Do not write “pixel-identical on both ends” as a success criterion. Write “same tasks, behavior following each system.”
- Verify by running a contrast task on device in Notes or Messages (select a phrase, share an image, edge-swipe back). Every step missing or warped in the self-drawn app is behavior paid in this swap. Log it as the architecture’s price, not as a random defect.
Related
- Same group: R4.14.2 Wrapping native controls produces drift in detailed behavior · R4.14.3 Accessibility and input methods are where cracks appear first
- Adjacent: R4.06 Platform convention vs brand consistency · R4.08 Core Apple HIG conventions
- Search terms:
renderer-for-behavior tradeoff·custom renderer·Flutter