Skip to content

Repository files navigation

Camera Cutout

A Flutter plugin for reading the position and drawable shape of a device camera cutout on Android and iOS.

Features

  • Returns cutout bounds in Flutter logical pixels relative to the application window.
  • Returns display-cutout safe insets and the current screen size.
  • Returns a drawable vector path when one is available.
  • Streams updated geometry after rotation and window-layout changes.
  • Distinguishes notches, hole punches, Dynamic Island, and unknown shapes.
  • Reports whether geometry is exact, estimated, or bounds-only.
  • Supports CocoaPods and Swift Package Manager.

Platform behavior

Platform Behavior
Android 12+ Reads DisplayCutout.cutoutPath and serializes the OS path into Flutter coordinates.
Android 9–11 Reads DisplayCutout.boundingRects and safe insets.
Android 7–8 Returns isSupported: false without failing the application.
iOS Resolves the hardware identifier against a bundled device catalog and returns estimated notch or Dynamic Island geometry.

UIKit exposes safe areas but does not expose iPhone sensor-housing geometry. The iOS catalog covers iPhone X through iPhone 17, iPhone Air, iPhone 16e, and iPhone 17e. Known iPhones without a cutout, iPads, and iPods return a supported result with an empty cutout list. An unknown future iPhone returns isSupported: false so callers can distinguish missing catalog data from a device that has no cutout.

Requirements

  • Flutter 3.38.0 or later
  • Dart 3.10.0 or later
  • Android API 24 or later
  • iOS 13.0 or later

Installation

dependencies:
  camera_cutout: <latest_version>

Then run:

flutter pub get

Usage

import 'dart:async';

import 'package:camera_cutout/camera_cutout.dart';

final cameraCutout = CameraCutout();
final info = await cameraCutout.getInfo();

for (final cutout in info.cutouts) {
  final bounds = cutout.bounds;
  final path = cutout.path?.toPath();
  final kind = cutout.kind;
  final accuracy = cutout.accuracy;
}

final subscription = cameraCutout.changes.listen((info) {
  for (final cutout in info.cutouts) {
    renderCutout(cutout.path?.toPath(), cutout.bounds);
  }
});

await subscription.cancel();

Drawing the shape

CameraCutoutPath.toPath() creates a dart:ui Path in screen coordinates. Use the returned path directly in a full-window CustomPainter. When path is null, draw the supplied bounds as the fallback.

void paintCutout(Canvas canvas, CameraCutoutGeometry cutout) {
  final path = cutout.path?.toPath() ?? Path()..addOval(cutout.bounds);
  canvas.drawPath(
    path,
    Paint()
      ..style = PaintingStyle.stroke
      ..strokeWidth = 2,
  );
}

Android edge-to-edge layout

The plugin only reads window geometry and does not change host layout policy. An overlay that must line up with a cutout should let its activity render into the cutout area.

class MainActivity : FlutterActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            window.attributes = window.attributes.apply {
                layoutInDisplayCutoutMode =
                    WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
            }
        }
    }
}

The included example selects LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS where Android supports it and uses Flutter's edge-to-edge system UI mode.

API

CameraCutout

  • Future<CameraCutoutInfo> getInfo() reads the current geometry.
  • Stream<CameraCutoutInfo> get changes emits geometry after relevant native layout changes.

CameraCutoutInfo

  • platform
  • deviceIdentifier
  • deviceModel
  • screenSize
  • devicePixelRatio
  • safeInsets
  • isSupported
  • cutouts
  • hasCutout
  • hasExactPath

CameraCutoutGeometry

  • bounds
  • kind
  • accuracy
  • path
  • hasPath

iOS catalog maintenance

The catalog is intentionally local and deterministic. Update it when Apple releases a new iPhone identifier, verify the display family against current Apple design resources or Simulator profiles, and add the identifier to the iOS catalog before publishing a new version.

Example

The example application draws the cutout shape at its physical screen position with a repeating glow animation and displays the returned bounds and accuracy.

Camera Cutout example outlining the hole-punch camera on a Nothing A063 in portrait orientation Camera Cutout example outlining the Dynamic Island on an iPhone 17 Pro in portrait orientation
Android
Exact OS path on a Nothing A063
iOS
Estimated catalog geometry on an iPhone 17 Pro

License

MIT

About

A Flutter plugin for reading camera cutout bounds, safe insets, and drawable shape geometry on Android and iOS.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages