SF Media Picker

A polished, Instagram-inspired media picker for Flutter. Let your users browse albums, preview photos or looping videos, and choose the perfect asset without leaving your custom UI. Built entirely in Dart with zero platform code.

Features

  • 🎨 Modern, high-contrast UI that feels right at home on iOS and Android
  • 📸 Unified picker for photos and videos with looping autoplay preview
  • 📁 Album switching with instant refresh when the device library changes
  • ♾️ Infinite scrolling grid with lazy paging
  • 🔌 Reusable widget – no Scaffold/AppBar so you own the surrounding UI
  • 🧩 Configurable preview height and grid density
  • ⚡ Pure Dart UI that works alongside existing photo_manager/video_player setups

Demo

SF Media Picker demo showing preview and grid

Installation

Add this to your package's pubspec.yaml file:

dependencies:
  sf_media_picker: ^1.0.2

Or install from a local path:

dependencies:
  sf_media_picker:
    path: ../path/to/sf_media_picker

Then run:

flutter pub get

Platform Setup

Since this package depends on photo_manager and video_player, you'll need to configure permissions in your app (not in this package). Follow the platform setup instructions for those plugins:

iOS

Add the following to your app's ios/Runner/Info.plist:

<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs access to your photo library to select images and videos.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>This app needs access to save photos to your library.</string>

Android

Add the following permissions to your app's android/app/src/main/AndroidManifest.xml:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />

For Android 13+ (API level 33+), you may also need:

<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />

Note: This package itself doesn't require any native configuration. All platform-specific setup is handled by the underlying photo_manager and video_player plugins that your app depends on.

Usage

Basic Example

The SFMediaPicker is a reusable widget that can be embedded anywhere in your app. It doesn't include a Scaffold or AppBar, giving you full control over the UI layout.

import 'package:flutter/material.dart';
import 'package:sf_media_picker/sf_media_picker.dart';

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: _MediaPickerScreen(),
    );
  }
}

class _MediaPickerScreen extends StatefulWidget {
  @override
  State<_MediaPickerScreen> createState() => _MediaPickerScreenState();
}

class _MediaPickerScreenState extends State<_MediaPickerScreen> {
  SfMediaAsset? _selected;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      appBar: AppBar(
        backgroundColor: Colors.black,
        title: const Text('Select Media'),
        actions: <Widget>[
          if (_selected != null)
            TextButton(
              onPressed: () {
                // Handle selected media
                print('Selected: ${_selected!.filePath}');
              },
              child: const Text(
                'Done',
                style: TextStyle(color: Colors.amber),
              ),
            ),
        ],
      ),
      body: SFMediaPicker(
        selectedAsset: _selected,
        onAssetSelected: (SfMediaAsset asset) {
          setState(() {
            _selected = asset;
          });
          debugPrint('Selected path: ${asset.filePath}');
        },
      ),
    );
  }
}

Widget Properties

Property Type Default Description
selectedAsset SfMediaAsset? null Asset to highlight when the picker loads.
onAssetSelected ValueChanged<SfMediaAsset>? null Callback fired whenever the selection changes.
previewHeightFactor double 0.35 Portion of available height dedicated to the preview. Must be between 0 and 1.
gridCrossAxisCount int 4 Number of columns in the asset grid.

Customisation

Tweak layout density or the preview size to better match your design language:

SFMediaPicker(
  previewHeightFactor: 0.45,
  gridCrossAxisCount: 3,
  onAssetSelected: (asset) => debugPrint('Selected: ${asset.id}'),
)

Working with Selected Media

// Get a playback-ready file (may be compressed by the platform)
final file = await asset.loadFile();

// Request the original file when you need the highest quality
final originalFile = await asset.loadFile(original: true);

// Fetch thumbnail bytes without relying on photo_manager directly
final thumbnail = await asset.loadThumbnail(width: 300, height: 300);

// Direct file system path, when available
final path = asset.filePath;
if (path != null) {
  print('Use the path directly: $path');
}

if (asset.isImage) {
  // Handle image-specific logic
} else if (asset.isVideo) {
  // Handle video-specific logic
}

Example

Check out the example directory for a complete working example.

Dependencies

This package depends on:

Package Structure

This is a pure Dart/Flutter package with no native code. It's lightweight and only contains:

  • lib/sf_media_picker.dart - Single entry-point export
  • lib/src/ - Widget implementation and private helpers
  • example/ - Example app demonstrating usage

No platform-specific folders (Android, iOS, macOS, Web, Windows, Linux) are included in the package itself, making it lightweight and easy to integrate.

The SFMediaPicker widget is a reusable component that can be embedded anywhere in your app. It doesn't include a Scaffold or AppBar, giving you complete control over the UI layout, navigation, and styling.

License

Released under the MIT License. See LICENSE for details.

Contributing

Issues and pull requests are welcome! Please file bugs or feature requests via the issue tracker.

Libraries

sf_media_picker