flutter_media_viewer 0.3.2 copy "flutter_media_viewer: ^0.3.2" to clipboard
flutter_media_viewer: ^0.3.2 copied to clipboard

Cached image and video gallery viewer with Hero transitions and playback controls.

flutter_media_viewer #

A cached image and video gallery viewer for Flutter with Hero transitions, playback controls, thumbnails, zoom, swipe-to-dismiss, and metadata details.

Features #

  • Displays images and videos in a full-screen gallery.
  • Opens with a Hero transition from a ready-to-use preview widget.
  • Shares cached network images between previews and the viewer.
  • Supports network URLs, file-system paths, and file: URIs.
  • Provides video play, pause, seek, mute, autoplay, and looping controls.
  • Shows available video durations on previews and gallery thumbnails.
  • Supports horizontal paging and a centered thumbnail strip.
  • Supports pinch-to-zoom for images.
  • Dismisses with an animated downward swipe.
  • Shows structured technical and location metadata.
  • Exposes optional share, delete, header, details, and custom actions.
  • Opens as a route or a full-page modal bottom sheet.
  • Accepts custom content and thumbnail builders.
  • Inherits the active application theme and supports scoped viewer themes.

Installation #

flutter pub add flutter_media_viewer

Import the public library:

import 'package:flutter_media_viewer/flutter_media_viewer.dart';

Quick Start #

Create one or more media items and render a FlutterMediaViewerPreview:

final List<FlutterMediaViewerItem> items = <FlutterMediaViewerItem>[
  const FlutterMediaViewerItem.image(
    id: 'photo-1',
    source: 'https://example.com/photo.jpg',
    thumbnailSource: 'https://example.com/photo-thumbnail.jpg',
    aspectRatio: 4 / 3,
    title: 'Coast',
    subtitle: 'Sunday, 4:53 PM',
  ),
];

FlutterMediaViewerPreview(
  items: items,
  initialIndex: 0,
  borderRadius: BorderRadius.circular(12),
  fit: BoxFit.cover,
);

FlutterMediaViewerPreview renders the selected item, owns the Hero transition, and opens the viewer when tapped. Set useModalBottomSheet to false to open it as a route instead. Previews use a 3 / 4 aspect ratio by default. Override the preview independently for square grids or other layouts without changing the media's intrinsic viewer ratio:

FlutterMediaViewerPreview(
  items: items,
  aspectRatio: 1,
);

Open Manually #

Use showModal when the preview already handles its own tap gesture:

await FlutterMediaViewer.showModal<void>(
  context,
  items: items,
  initialIndex: selectedIndex,
  config: FlutterMediaViewerConfig(
    showThumbnails: items.length > 1,
    closeTooltip: 'Close',
  ),
);

Use FlutterMediaViewer.show for route presentation, or place FlutterMediaViewer directly in an existing widget tree.

Video #

Create a video item with its source and an optional thumbnail:

const FlutterMediaViewerItem.video(
  id: 'video-1',
  source: 'https://example.com/video.mp4',
  thumbnailSource: 'https://example.com/video-thumbnail.jpg',
  aspectRatio: 9 / 16,
);

The built-in player pauses when its page is no longer active. Playback behavior is configured through FlutterMediaViewerConfig:

const FlutterMediaViewerConfig(
  enableZoom: false,
  enableVideoAutoplay: true,
  enableVideoLooping: true,
  showVideoControls: true,
  startVideosMuted: true,
);

Disable enableZoom for galleries containing videos or custom gesture-heavy content. Built-in videos start muted by default; set startVideosMuted to false when sound should start immediately.

Cached Previews And Placeholders #

Use FlutterMediaPreview when only the media preview is needed. Use FlutterMediaHero to wrap a completely custom preview while retaining the viewer transition.

Each item can define cache keys, request headers, and file-system placeholders:

const FlutterMediaViewerItem.image(
  id: 'photo-2',
  source: 'https://example.com/photo-2.jpg',
  thumbnailSource: 'https://example.com/photo-2-thumbnail.jpg',
  localPlaceholderSource: '/temporary/photo-2.jpg',
  thumbnailLocalPlaceholderSource: '/temporary/photo-2-thumbnail.jpg',
  cacheKey: 'photo-2',
  thumbnailCacheKey: 'photo-2-thumbnail',
  httpHeaders: <String, String>{
    'Authorization': 'Bearer token',
  },
);

The local placeholder remains visible while the remote source loads and fades smoothly into the cached remote image.

Theming #

The viewer inherits the active ThemeData.colorScheme by default, including the application's current light or dark mode.

Use themeMode only when a viewer must use a specific brightness independently from the surrounding application:

const FlutterMediaViewerConfig(
  themeMode: ThemeMode.dark,
);

Use FlutterMediaViewerThemeData for a complete per-viewer color scheme:

const FlutterMediaViewerConfig(
  theme: FlutterMediaViewerThemeData(
    colorScheme: ColorScheme.dark(
      primary: Color(0xFF8AB4F8),
    ),
    mediaBackgroundColor: Colors.black,
  ),
);

Add the same extension to an application's ThemeData.extensions to configure all viewers under that theme:

ThemeData(
  colorScheme: const ColorScheme.dark(),
  extensions: const <ThemeExtension<dynamic>>[
    FlutterMediaViewerThemeData(
      colorScheme: ColorScheme.dark(),
    ),
  ],
);

The optional backgroundColor and controlsBackgroundColor configuration values remain available as focused overrides. Leaving them unset allows the viewer theme and application color scheme to resolve them.

Relative Sources #

Absolute HTTP(S) URLs are recommended. Relative sources can be resolved with sourceUrlBuilder:

final FlutterMediaViewerConfig config = FlutterMediaViewerConfig(
  sourceUrlBuilder: (String source) {
    return Uri.parse('https://cdn.example.com/').resolve(source).toString();
  },
);

The same resolver is used for full media and thumbnail sources.

Metadata #

Use FlutterMediaViewerMetadata for the built-in details panel:

const FlutterMediaViewerItem.image(
  id: 'photo-3',
  source: 'https://example.com/photo-3.jpg',
  metadata: FlutterMediaViewerMetadata(
    dateText: 'Sunday, September 6, 2026 at 4:53 PM',
    fileName: 'IMG_3957.HEIC',
    device: 'Phone camera',
    format: 'HEIF',
    camera: 'Wide camera',
    summary: '12 MP - 3024 x 4032 - 3.3 MB',
    badges: <String>['LIVE'],
    exposure: <String>['ISO 125', '26 mm', 'f/1.8', '1/97 s'],
    locationName: 'Coast',
    latitude: 37.77,
    longitude: -122.42,
  ),
);

All metadata values are display-ready. Empty fields and sections are omitted. The package validates coordinates but does not extract EXIF data, request location permission, geocode coordinates, or select a map provider.

Use locationPreviewBuilder to render a map preview and onLocationPressed to handle the location row. Use detailsBuilder to replace the complete details panel.

A Map<String, String> can be supplied as metadata when a simple list of localized labels and values is sufficient.

Optional Actions #

Share and delete controls are shown only when their callbacks are configured:

final FlutterMediaViewerConfig config = FlutterMediaViewerConfig(
  onSharePressed: handleShare,
  onDeletePressed: handleDelete,
);

Callbacks receive the active FlutterMediaViewerOverlayInfo. File sharing, confirmation, and deletion remain explicit so the package never changes stored media by itself.

The package uses Hugeicons and a platform-aware BackButtonIcon as fallbacks. Every built-in action icon can be replaced without rebuilding the action bars:

final FlutterMediaViewerConfig config = FlutterMediaViewerConfig(
  onSharePressed: handleShare,
  closeIconBuilder: (BuildContext context) => const Icon(Icons.arrow_back),
  shareIconBuilder: (BuildContext context) => const Icon(Icons.ios_share),
  infoIconBuilder: (BuildContext context) => const Icon(Icons.info_outline),
  deleteIconBuilder: (BuildContext context) => const Icon(Icons.delete_outline),
  playIconBuilder: (BuildContext context) => const Icon(Icons.play_arrow),
  pauseIconBuilder: (BuildContext context) => const Icon(Icons.pause),
  muteIconBuilder: (BuildContext context) => const Icon(Icons.volume_off),
  unmuteIconBuilder: (BuildContext context) => const Icon(Icons.volume_up),
);

Configuration #

Option Default Description
showControlsInitially true Shows controls when the viewer opens.
showThumbnails true Shows thumbnail navigation for galleries.
showHeader true Shows non-empty item titles and subtitles.
showCloseButton true Shows the platform-aware back button.
enableSwipeDownToDismiss true Enables downward drag dismissal.
backgroundColor null Overrides the media background, which defaults to black.
controlsBackgroundColor null Overrides the themed controls and details surface.
themeMode null Optionally forces light, dark, or system brightness.
theme null Overrides the inherited FlutterMediaViewerThemeData.
constrainedMediaBorderRadius 24 px Radius applied only when tall media is constrained.
imageFit BoxFit.contain Fit used by built-in media.
thumbnailFit BoxFit.cover Fit used by built-in thumbnails.
enableZoom true Enables InteractiveViewer.
minScale 1 Minimum zoom scale.
maxScale 4 Maximum zoom scale.
enableVideoAutoplay true Autoplays the active video.
enableVideoLooping true Loops built-in videos.
showVideoControls true Shows playback, timeline, and mute controls.
startVideosMuted true Starts built-in videos muted.
showBottomActionBar true Allows configured bottom actions.
sourceUrlBuilder null Resolves relative sources.
topActionsBuilder null Builds additional top actions.
bottomActionsBuilder null Builds additional bottom actions.
onSharePressed null Shows and handles the share action.
onDeletePressed null Shows and handles the delete action.
detailsBuilder null Replaces the details panel.
locationPreviewBuilder null Builds an optional location preview.
onLocationPressed null Handles the location row.

The close, share, info, delete, play, pause, muted, and unmuted icons each have an optional WidgetBuilder in FlutterMediaViewerConfig. Leaving a builder unset keeps the package fallback icon.

All visible labels and tooltips can be supplied through FlutterMediaViewerConfig for localization.

Custom Content #

Use the base FlutterMediaViewerItem constructor with contentBuilder and thumbnailBuilder for unsupported formats, DRM, or specialized rendering. Built-in image and video rendering is used when those builders are omitted.

Layout Behavior #

Pass the media width-to-height aspectRatio whenever it is available. The built-in image and video renderers can resolve it after loading when omitted.

Tall media is constrained only when its full-width height would overlap the top or bottom controls. Its intrinsic aspect ratio determines the resulting width, with rounded corners and a subtle border in that constrained state. Media that fits remains full width. Opening details expands the active media over the available upper area with BoxFit.cover; closing details restores its previous frame and fit. Hiding the controls removes the constrained border and radius, expands the media canvas to the available viewer area, and uses BoxFit.contain for both images and videos.

Example #

The example directory demonstrates images, videos, metadata, thumbnails, custom builders, actions, and both presentation modes.

License #

MIT License. See LICENSE.

1
likes
150
points
164
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Cached image and video gallery viewer with Hero transitions and playback controls.

Repository (GitHub)
View/report issues

Topics

#gallery #media #photos #videos #viewer

License

MIT (license)

Dependencies

cached_network_image_ce, flutter, hugeicons, video_player

More

Packages that depend on flutter_media_viewer