Writing

Rendering Native Content in Flutter: Platform Views vs Texture Widget

FlutterAndroidiOSPlatform ViewsTexture

Originally published on Medium.

A practical guide to the two primary ways to display native Android/iOS content inside Flutter, illustrated with a camera SDK example.

Why Flutter needs native rendering

Flutter renders almost everything itself using Skia (or Impeller on newer versions). Widgets, animations, buttons — all painted by Flutter’s own engine onto a single canvas.

But some SDKs expose mature native UI components that Flutter simply cannot repaint:

  • Camera
  • Maps
  • WebView
  • Video player
  • AR SDKs
  • Payment SDKs

Flutter needs a bridge: a way to host or consume native output without giving up control of the rest of the screen.

All rendering approaches

Flutter provides several mechanisms for native rendering. Two are primary (covered in depth in this guide); the rest are specialised.

Approach What it does Typical use
Platform Views Embeds a real native View (Android) or UIView (iOS) inside Flutter’s widget tree Maps, WebView, payment SDKs
Texture widget Displays GPU-produced pixel frames from native code. No View hierarchy Camera, video, OpenGL/Vulkan
Hybrid Composition Modern Platform View variant. Flutter places a real Android View in the hierarchy with correct z-order and accessibility Modern Android native views
Virtual Display Older Platform View variant. Native view renders into a virtual off-screen display. Largely superseded by Hybrid Composition Older Android versions
Platform Channels only No native rendering at all. Flutter draws the UI, native handles logic Bluetooth, NFC, biometrics, sensors
Bitmap / screenshot Native renders to a bitmap; Flutter displays it via Image.memory(). Unsuitable for live or interactive content Charts, PDF previews

This guide focuses on Platform Views and Texture widget — the two primary techniques for live native rendering in Flutter.

Approach 1: Platform Views

What is a Platform View?

A Platform View embeds an actual native view inside Flutter. On Android this means View, SurfaceView, PreviewView, WebView, MapView, and so on. On iOS it wraps a UIView.

Flutter reserves an area on screen while the OS renders the native view. Think of it as a mini native app embedded inside your widget tree.

Architecture

Flutter never draws the camera preview. Android does.

Flutter widget tree


   AndroidView / UiKitView


 Native View (PreviewView, MapView, WebView…)


 OS layout, drawing, measuring, touch

Rendering pipeline

Android owns layout, drawing, measuring, and touch events. Flutter only owns positioning.

SDK / CameraX  →  PreviewView (native)


              Platform View hole in Flutter


              User sees native pixels in place

Touch / event flow

Because the native view is real, the OS delivers gestures to it first. Flutter is not the owner of those events inside the hole.

Camera example (Platform View)

AndroidView(
  viewType: 'camera_preview',
)
┌────────────────────────────┐
│  Text / Buttons            │
│                            │
│  AndroidView               │
│  ┌────────────────────┐    │
│  │   PreviewView      │    │
│  │   (native Android) │    │
│  └────────────────────┘    │
│                            │
│  Capture Button            │
└────────────────────────────┘

The preview you see is PreviewView, not Flutter.

Advantages

  • Supports any native UI component
  • Native accessibility out of the box
  • Native gesture handling
  • Existing SDK works without modification
  • Easy integration path

Drawbacks

  • Higher rendering cost
  • More expensive during scrolling
  • More memory usage
  • Complex view composition

Approach 2: Texture widget

What is a Texture?

A Texture is not a View. That is the biggest misconception.

The Texture widget simply displays pixels produced by native code. Flutter does not know (or care) whether those pixels came from a camera, a video decoder, OpenGL, Vulkan, or a game engine.

No Android View hierarchy is involved at all. Frames flow from native code through a SurfaceTexture into Flutter’s TextureRegistry, which assigns a numeric ID. Flutter’s Texture widget renders that GPU texture directly.

Architecture

Notice what is missing: there is no Android View.

Camera / CameraX / decoder / OpenGL


  SurfaceTexture  (native draws frames)


  TextureRegistry (Flutter assigns textureId)


  Texture(textureId: id)  ← Flutter paints GPU pixels

Rendering pipeline

Flutter only paints a GPU texture. Nothing else. That is why this path is cheaper than composing a real native view.

Touch / gesture flow

Because there is no native View, Flutter must handle all gestures. They are forwarded via MethodChannel to native code:

User touch


Flutter GestureDetector


MethodChannel


Native camera (zoom, flash, capture)

Camera example (Texture)

Texture(
  textureId: textureId,
)
┌───────────────────────────────┐
│                               │
│     Flutter Widgets           │
│                               │
│  ┌─────────────────────────┐  │
│  │                         │  │
│  │    Texture Widget       │  │  ← GPU pixels, no View
│  │                         │  │
│  └─────────────────────────┘  │
│                               │
│  Flutter Capture Button       │
└───────────────────────────────┘

Advantages

  • Extremely smooth rendering
  • Lower latency
  • Better scrolling and animations
  • Great for video and camera preview
  • No view hierarchy overhead

Drawbacks

  • Not interactive: pixels only
  • No native controls or text fields
  • Flutter must implement all gestures
  • Extra communication via platform channels

Side-by-side comparison

Platform Views Texture widget
What you embed A real Android View / iOS UIView GPU frames (pixels only)
Who draws The OS Flutter paints a texture
View hierarchy Yes No
Touch Native view handles it Flutter, then MethodChannel
Accessibility Native, out of the box You build it in Flutter
Best for Maps, WebView, payment UI Camera, video, OpenGL/Vulkan
Cost Higher (composition, memory, scroll) Lower latency, smoother

Camera SDK: which approach does the industry use?

Most camera Flutter plugins (including the official camera package) use the Texture approach for the live preview. It delivers smoother 60fps rendering and lower latency.

Flutter widgets are overlaid on top for the capture button, zoom slider, and flash controls.

Combined architecture used in real plugins:

Flutter
 ├── GestureDetector     (pinch-to-zoom, etc.)
 ├── Texture Widget      (live camera preview via GPU)
 └── Flutter UI widgets  (capture button, timer, etc.)

Android
 ├── Camera / CameraX
 ├── SurfaceTexture      (frame production)
 └── TextureRegistry     (bridges frames to Flutter)

Communication
 └── MethodChannel / EventChannel  (zoom, flash, capture, events)

SurfaceTexture is the canvas where native code draws frames. TextureRegistry is Flutter’s manager that registers and exposes those canvases to Flutter.

When to use which

Choose Platform View when:

  • You need a real Android/iOS View
  • The SDK already exposes a View
  • Native gestures are required
  • Accessibility support is needed
  • You are embedding WebView, Maps, or a payment SDK

Choose Texture widget when:

  • Rendering camera frames
  • Playing video
  • Rendering OpenGL or Vulkan content
  • Performance and latency are critical
  • No native UI hierarchy is needed

Key takeaways

  • Platform Views embed an actual native View inside Flutter. Android/iOS owns layout, drawing, measuring, and touch events. Flutter only owns positioning.
  • Texture displays only GPU-rendered pixels. No View hierarchy. No layout overhead. Just frames.
  • Platform Views are ideal for interactive native UI (WebView, Maps, payment sheets).
  • Texture is ideal for high-performance rendering (camera preview, video playback, AR/OpenGL).
  • In real-world plugins, these two approaches are often combined: Texture for rendering, platform channels for control, Flutter widgets for the UI layer on top.

All writing →