flutter_media_viewer 0.4.2 copy "flutter_media_viewer: ^0.4.2" to clipboard
flutter_media_viewer: ^0.4.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 and animated double-tap zoom for images and videos.
  • Displays Live Photos as still images with hold-to-play motion and a LIVE badge.
  • 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 custom gesture-heavy content when needed. Built-in videos start muted by default; set startVideosMuted to false when sound should start immediately.

Live Photos #

Provide an independently displayable still image and its paired motion file:

const FlutterMediaViewerItem.livePhoto(
  id: 'live-photo-1',
  source: 'https://example.com/photo.jpg',
  motionSource: 'https://example.com/motion.mov',
  thumbnailSource: 'https://example.com/thumbnail.jpg',
  aspectRatio: 3 / 4,
);

The preview shows a compact Live Photo symbol instead of a play button or duration. Tap that symbol to play motion without opening the viewer. Long presses remain available to the enclosing application's context menu. The thumbnail navigation strip stays still and does not create players.

The viewer plays motion once on opening, independently of video autoplay. Set enableLivePhotoAutoplay: false to require a long press instead. Holding the photo replays its motion; releasing it restores the still image. The LIVE menu supports Live, Loop, and Off. Motion is muted and pauses when the page or app becomes inactive. motionLocalPlaceholderSource can point to a downloaded motion file while motionSource retains the remote fallback. The host remains responsible for authorization, download, and saving the original pair to the platform photo library.

Use livePhotoMotionLoader to resolve a private or expired motion URL to an authorized URL or local file URI when playback is requested. It runs for each active item, not only the initial gallery item. The still remains visible while resolution is pending; failed resolution can be retried by replaying the photo.

Use livePhotoModePicker to present your own menu and return a FlutterMediaViewerLivePhotoMode, or null on dismissal. Without an override, the package presents a Cupertino action sheet. Loop repeats the motion file; Bounce and Long Exposure are not offered because they require additional media processing. Labels are configurable through livePhotoLabel, livePhotoLoopLabel, and stillPhotoLabel.

Zoom hides all viewer controls until the original scale is restored, preserving whether controls were visible before zooming.

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,
  onMorePressed: handleMore,
);

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.
onMorePressed null Shows the upper-right menu button; the host supplies its actions.
moreTooltip More Accessible menu button label.
livePhotoLabel / stillPhotoLabel LIVE / Still Localized Live Photo mode labels.
livePhotoLoopLabel Loop Localized looping mode label.
enableLivePhotoAutoplay true Plays active Live motion once, independently of video autoplay.
livePhotoMotionLoader null Lazily resolves an item's motion to an authorized URL or local file URI.
livePhotoModePicker null Replaces the Live mode action sheet with an application-owned menu.
loadingBuilder null Replaces the built-in video loading indicator.
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.

2
likes
150
points
399
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