medias_viewer 0.6.1
medias_viewer: ^0.6.1 copied to clipboard
A powerful and customizable Flutter media viewer for images and videos with zoom, swipe navigation, and video controls.
Medias Viewer #
A powerful and customizable Flutter media viewer for images, videos, YouTube and Vimeo videos with zoom, swipe navigation, and video controls.
Features #
β¨ Image Support
- Zoom with pinch-to-zoom and double-tap
- Pan and navigate zoomed images
- Support for network, local files, and assets
- High-resolution image support with caching
- Hero animations
π¬ Video Support
- Auto-pause when swiping away
- Full playback controls (play, pause, seek)
- Fullscreen support
- Support for network, local files, and assets
- Custom video player with Chewie
- SafeArea-aware controls (notch-friendly)
- Smart navigation arrows (auto-hide during video playback)
- Configurable back button positioning
πΊ YouTube Support
- Play YouTube videos directly in the viewer
- Auto-detection of YouTube URLs (youtube.com, youtu.be)
- Integrated player without external browser
- Full support for autoPlay, controls, and fullscreen
- Optimized for Android and iOS with excellent mobile performance
- Seamless navigation with other media types
- Simple and fluid integration with better mobile compatibility
π₯ Vimeo Support
- Play Vimeo videos directly in the viewer
- Auto-detection of Vimeo URLs (vimeo.com, player.vimeo.com)
- Integrated player without external browser
- High-quality video streaming
- Seamless navigation with other media types
- Simple integration with mobile-optimized playback
π¨ Customization
- Custom background colors
- Configurable page indicator (position, style, colors)
- Navigation arrows (left/right) with customizable position
- Back/Close button
- Enable/disable zoom
- Enable/disable loop navigation
- Auto-play videos option
- Custom indicator styles
- Swipe down to dismiss
β‘ Performance
- Optimized memory management
- Efficient video controller disposal
- Smooth page transitions
- Network image caching
- Improved swipe detection (horizontal vs vertical)
π― User Experience
- SafeArea support for all controls (notch-friendly)
- Swipe down gesture to close viewer
- Optional navigation arrows for manual control
- Configurable swipe sensitivity
- Smooth transitions between zoomed images
π± Platform Support
- β Android
- β iOS
- β Desktop (macOS)
Installation #
Add this to your package's pubspec.yaml file:
dependencies:
medias_viewer: ^0.4.0
Then run:
flutter pub get
Usage #
Basic Example #
import 'package:flutter/material.dart';
import 'package:medias_viewer/medias_viewer.dart';
class MyGallery extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MediaViewer(
items: [
MediaItem.imageUrl('https://example.com/image1.jpg'),
MediaItem.imageUrl('https://example.com/image2.jpg'),
MediaItem.videoUrl('https://example.com/video.mp4'),
],
onDismissed: () => Navigator.pop(context),
);
}
}
Example with Auto-Detection #
import 'package:flutter/material.dart';
import 'package:medias_viewer/medias_viewer.dart';
class MyGallery extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MediaViewer(
items: [
// Type is automatically detected from file extension
MediaItem.url('https://example.com/photo1.jpg'),
MediaItem.url('https://example.com/photo2.png'),
MediaItem.url('https://example.com/video.mp4'),
MediaItem.url('https://example.com/clip.mov'),
],
config: MediaViewerConfig(
enableAutoDetectMediaType: true, // Enable auto-detection
),
onDismissed: () => Navigator.pop(context),
);
}
}
Advanced Example #
MediaViewer(
items: [
MediaItem.imageUrl('https://example.com/image1.jpg', tag: 'hero1'),
MediaItem.videoUrl('https://example.com/video.mp4'),
MediaItem.youtubeUrl('https://www.youtube.com/watch?v=dQw4w9WgXcQ'),
MediaItem.vimeoUrl('https://vimeo.com/76979871'),
MediaItem.imagePath('/path/to/local/image.jpg'),
MediaItem.imageAsset('assets/images/photo.png'),
],
initialIndex: 0,
config: MediaViewerConfig(
backgroundColor: Colors.black,
showIndicator: true,
indicatorPosition: IndicatorPosition.topCenter,
indicatorStyle: IndicatorStyle(
textStyle: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
backgroundColor: Colors.black54,
borderRadius: 16,
),
enableLoop: false,
enableImageZoom: true,
enableDoubleTapZoom: true,
minScale: 1.0,
maxScale: 3.0,
autoPlayVideo: true,
showVideoControls: true,
allowFullScreen: true,
onPageChanged: (index) => print('Page changed to $index'),
),
onDismissed: () => Navigator.pop(context),
);
YouTube Video Example #
import 'package:flutter/material.dart';
import 'package:medias_viewer/medias_viewer.dart';
class YouTubeGallery extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MediaViewer(
items: [
MediaItem.youtubeUrl('https://www.youtube.com/watch?v=dQw4w9WgXcQ'),
MediaItem.imageUrl('https://example.com/photo.jpg'),
MediaItem.youtubeUrl('https://youtu.be/9bZkp7q19f0'),
],
config: MediaViewerConfig(
autoPlayVideo: true,
allowFullScreen: true,
showBackButton: true,
enableDismissOnSwipeDown: true,
),
onDismissed: () => Navigator.pop(context),
);
}
}
Vimeo Video Example #
import 'package:flutter/material.dart';
import 'package:medias_viewer/medias_viewer.dart';
class VimeoGallery extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MediaViewer(
items: [
MediaItem.vimeoUrl('https://vimeo.com/76979871'),
MediaItem.imageUrl('https://example.com/photo.jpg'),
MediaItem.vimeoUrl('https://player.vimeo.com/video/148751763'),
],
config: MediaViewerConfig(
autoPlayVideo: true,
allowFullScreen: true,
showBackButton: true,
enableDismissOnSwipeDown: true,
),
onDismissed: () => Navigator.pop(context),
);
}
}
New Features Examples #
Video UX Optimizations
The package now includes several video-specific UX improvements:
MediaViewer(
items: [
MediaItem.videoUrl('https://example.com/video.mp4'),
// ... other items
],
config: MediaViewerConfig(
// Automatically hide navigation arrows when video is playing
hideArrowsWhenVideoPlays: true, // Default: true
// Adjust back button position to avoid overlap with fullscreen button
backButtonPadding: EdgeInsets.only(top: 16, left: 8), // Default
// Video controls automatically respect SafeArea (notch-friendly)
showVideoControls: true,
),
);
What's improved:
- β Video controls respect device SafeArea (no more controls hidden behind notches)
- β Navigation arrows automatically fade out during video playback for unobstructed viewing
- β Back button position is configurable to prevent overlap with Chewie's fullscreen button
- β Smooth fade animations (300ms) for better user experience
With Navigation Arrows
MediaViewer(
items: [...],
config: MediaViewerConfig(
showNavigationArrows: true,
navigationArrowsPosition: NavigationArrowsPosition.centerVertical,
arrowsColor: Colors.white,
arrowsSize: 40,
),
);
With Back Button
MediaViewer(
items: [...],
config: MediaViewerConfig(
showBackButton: true,
backButtonColor: Colors.white,
),
onDismissed: () => Navigator.pop(context),
);
Swipe Down to Dismiss
MediaViewer(
items: [...],
config: MediaViewerConfig(
enableDismissOnSwipeDown: true,
),
onDismissed: () => Navigator.pop(context),
);
Full Featured Gallery
MediaViewer(
items: [...],
config: MediaViewerConfig(
// Navigation controls
showNavigationArrows: true,
navigationArrowsPosition: NavigationArrowsPosition.centerVertical,
showBackButton: true,
// Dismiss gesture
enableDismissOnSwipeDown: true,
// Indicator
showIndicator: true,
indicatorPosition: IndicatorPosition.topCenter,
indicatorStyle: IndicatorStyle(
backgroundColor: Colors.black54,
borderRadius: 16,
),
// Behavior
autoPlayVideo: true,
enableLoop: false,
),
onDismissed: () => Navigator.pop(context),
);
Creating Media Items #
Auto-Detection (Recommended)
The simplest way to create media items is to use automatic type detection based on file extensions:
// Automatic detection from URL
MediaItem.url('https://example.com/photo.jpg') // Detected as image
MediaItem.url('https://example.com/video.mp4') // Detected as video
// Automatic detection from local path
MediaItem.path('/storage/photos/image.png') // Detected as image
MediaItem.path('/storage/videos/clip.mov') // Detected as video
// Automatic detection from asset
MediaItem.asset('assets/images/photo.jpg') // Detected as image
MediaItem.asset('assets/videos/intro.mp4') // Detected as video
Supported Extensions:
- Images: jpg, jpeg, png, gif, webp, bmp, svg
- Videos: mp4, mov, avi, mkv, webm, flv, m4v, wmv
Note: If the extension is not recognized, an UnsupportedError will be thrown with a helpful message listing all supported formats. For future versions, we plan to add HTTP Content-Type detection for even better reliability with network URLs.
Manual Type Specification
You can also explicitly specify the media type (useful when auto-detection isn't suitable):
Images
// Network image
MediaItem.imageUrl('https://example.com/image.jpg')
// Network image with hero tag
MediaItem.imageUrl('https://example.com/image.jpg', tag: 'hero_tag')
// Local file
MediaItem.imagePath('/path/to/image.jpg')
// Asset
MediaItem.imageAsset('assets/images/photo.png')
Videos
// Network video
MediaItem.videoUrl('https://example.com/video.mp4')
// Local file video
MediaItem.videoPath('/path/to/video.mp4')
// Asset video
MediaItem.videoAsset('assets/videos/intro.mp4')
YouTube Videos
// YouTube video from standard URL
MediaItem.youtubeUrl('https://www.youtube.com/watch?v=dQw4w9WgXcQ')
// YouTube video from short URL
MediaItem.youtubeUrl('https://youtu.be/dQw4w9WgXcQ')
// YouTube video with auto-detection
MediaItem.url('https://www.youtube.com/watch?v=dQw4w9WgXcQ')
// YouTube video starting at a specific time (90 seconds = 1min30s)
MediaItem.youtubeUrl('https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=90')
// Short URL with start time (30 seconds)
MediaItem.youtubeUrl('https://youtu.be/dQw4w9WgXcQ?t=30')
Supported YouTube URL formats:
https://www.youtube.com/watch?v=VIDEO_IDhttps://youtube.com/watch?v=VIDEO_IDhttps://m.youtube.com/watch?v=VIDEO_IDhttps://youtu.be/VIDEO_IDyoutube.com/watch?v=VIDEO_ID(without protocol)
Note: Make sure to add youtube_player_flutter to your dependencies. The package is compatible with Android and iOS platforms, with excellent mobile performance.
Vimeo Videos
// Vimeo video from standard URL
MediaItem.vimeoUrl('https://vimeo.com/76979871')
// Vimeo video from player URL
MediaItem.vimeoUrl('https://player.vimeo.com/video/148751763')
// Vimeo video with auto-detection
MediaItem.url('https://vimeo.com/76979871')
Supported Vimeo URL formats:
https://vimeo.com/VIDEO_IDhttps://www.vimeo.com/VIDEO_IDhttps://player.vimeo.com/video/VIDEO_IDvimeo.com/VIDEO_ID(without protocol)
Note: Make sure to add vimeo_video_player to your dependencies. The package provides high-quality video streaming for mobile platforms.
Configuration Options #
| Property | Type | Default | Description |
|---|---|---|---|
backgroundColor |
Color |
Colors.black |
Background color of the viewer |
showIndicator |
bool |
true |
Show page indicator (e.g., "1 of 5") |
indicatorPosition |
IndicatorPosition |
topCenter |
Position of the indicator |
indicatorStyle |
IndicatorStyle? |
null |
Custom style for the indicator |
enableLoop |
bool |
false |
Enable infinite loop navigation |
enableImageZoom |
bool |
true |
Enable zoom for images |
enableDoubleTapZoom |
bool |
true |
Enable double-tap to zoom |
minScale |
double |
1.0 |
Minimum zoom scale |
maxScale |
double |
3.0 |
Maximum zoom scale |
autoPlayVideo |
bool |
false |
Auto-play videos when displayed |
showVideoControls |
bool |
true |
Show video playback controls |
allowFullScreen |
bool |
true |
Allow fullscreen video |
pageSnapping |
bool |
true |
Enable page snapping |
onPageChanged |
Function(int)? |
null |
Callback when page changes |
showNavigationArrows |
bool |
false |
Show left/right navigation arrows |
navigationArrowsPosition |
NavigationArrowsPosition |
centerVertical |
Position of navigation arrows |
arrowsColor |
Color |
Colors.white |
Color of navigation arrows |
arrowsSize |
double |
40 |
Size of navigation arrows |
showBackButton |
bool |
false |
Show back/close button |
backButtonColor |
Color |
Colors.white |
Color of back button |
backButtonPadding |
EdgeInsets |
EdgeInsets.only(top: 16, left: 8) |
Padding for back button positioning |
enableDismissOnSwipeDown |
bool |
false |
Enable swipe down to dismiss |
swipeToPageThreshold |
double |
0.6 |
Swipe sensitivity (0.0 to 1.0) |
enableAutoDetectMediaType |
bool |
false |
Enable automatic media type detection from file extensions |
hideArrowsWhenVideoPlays |
bool |
true |
Automatically hide navigation arrows during video playback |
enableAutoDetectMediaType |
bool |
true |
Automatically detect the media type |
Indicator Positions #
IndicatorPosition.topLeftIndicatorPosition.topCenterIndicatorPosition.topRightIndicatorPosition.bottomLeftIndicatorPosition.bottomCenterIndicatorPosition.bottomRight
Navigation Arrows Positions #
NavigationArrowsPosition.centerVerticalNavigationArrowsPosition.topNavigationArrowsPosition.bottom
Example App #
Check out the example directory for a complete demo app with various use cases:
- Basic image gallery
- Mixed media (images and videos)
- Custom configurations
- Gallery with zoom disabled
- Video gallery with autoplay
- Grid gallery with hero animations
- Gallery with navigation arrows
- Gallery with back button
- Swipe down to dismiss gallery
- Full featured gallery (all options enabled)
To run the example:
cd example
flutter pub get
flutter run
API Reference #
MediaViewer #
The main widget for displaying media.
Constructor Parameters:
items(required): List ofMediaItemobjects to displayinitialIndex: Starting index (default: 0)config: Configuration object for customizationonDismissed: Callback when viewer is dismissed
MediaItem #
Represents a media item (image or video).
Constructors:
MediaItem.imageUrl(String url, {String? tag})MediaItem.imagePath(String path, {String? tag})MediaItem.imageAsset(String assetPath, {String? tag})MediaItem.videoUrl(String url)MediaItem.videoPath(String path)MediaItem.videoAsset(String assetPath)MediaItem.youtubeUrl(String url)- NEW in v0.4.0MediaItem.url(String url, {String? tag})- Auto-detection (includes YouTube support)MediaItem.path(String path, {String? tag})- Auto-detection for local filesMediaItem.asset(String assetPath, {String? tag})- Auto-detection for assets
MediaViewerConfig #
Configuration for the media viewer.
See the Configuration Options table above for all available properties.
IndicatorStyle #
Style configuration for the page indicator.
Properties:
textStyle: Text style for the indicatorpadding: Padding around the indicatorbackgroundColor: Optional background colorborderRadius: Border radius for the background
Performance Tips #
- Image Caching: Network images are automatically cached using
cached_network_image - Video Memory: Video controllers are properly disposed when swiping away
- Large Galleries: The package efficiently handles large numbers of media items
- Lazy Loading: Media items are loaded on-demand as you swipe
Requirements #
- Flutter >= 3.24.0
- Dart >= 3.9.2
Dependencies #
photo_view: ^0.15.0 - Image zoom and panvideo_player: ^2.9.2 - Video playbackchewie: ^1.8.5 - Custom video player with controlsyoutube_player_flutter: 9.1.3 - YouTube video playback (optimized for mobile)cached_network_image: ^3.4.1 - Network image caching
Contributing #
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Issues #
If you encounter any issues or have feature requests, please file them in the issue tracker.
License #
This project is licensed under the MIT License - see the LICENSE file for details.
Author #
BRIX - GitHub
Changelog #
See CHANGELOG.md for a list of changes in each version.
Acknowledgments #
- Built with Flutter
- Uses photo_view for image zoom
- Uses video_player and chewie for video playback
- Uses cached_network_image for efficient image caching