|
|
||
|---|---|---|
| .github | ||
| docs | ||
| example | ||
| lib | ||
| test | ||
| .gitignore | ||
| .metadata | ||
| LICENSE | ||
| README.md | ||
| analysis_options.yaml | ||
| changelog.rst | ||
| pubspec.yaml | ||
| splash_video.iml | ||
README.md
splash_video
A Flutter package for creating smooth video splash screens using media_kit. Provides seamless transitions from native splash screens to video playback with flexible overlay support and manual controls.
Platform Support
| Platform | Supported |
|---|---|
| Android | ✅ |
| iOS | ✅ |
| macOS | ✅ |
| Windows | ✅ |
| Linux | ✅ |
Features
- ✨ Smooth Transitions - Defer first frame pattern prevents jank between native and video splash
- 🎬 Media Kit Integration - Cross-platform video playback with hardware acceleration
- 🎮 Manual Controls - Full controller access for play, pause, skip operations
- 🔄 Looping Support - Infinite video loops with user-controlled exit
- 📱 Flexible Overlays - Title, footer, and custom overlay widgets
- 🎯 Auto-Navigation - Automatic screen transitions or manual control
- 🎨 7 Scale Modes - Cover, contain, fill, fitWidth, fitHeight, scaleDown, none
- 📐 Aspect Ratio Control - Full control over video sizing and scaling strategies
- ⚡ Hardware Acceleration - Smart platform defaults with 9 configurable decode modes
Installation
Add to your pubspec.yaml:
dependencies:
splash_video: ^0.1.3
## Quick Start
### 1. Initialize in main()
```dart
import 'package:flutter/material.dart';
import 'package:media_kit/media_kit.dart';
import 'package:splash_video/splash_video.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
// Required: Initialize media_kit
SplashVideo.initialize();
runApp(MyApp());
}
2. Basic Usage (Auto-Navigate)
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: SplashVideo(
source: AssetSource('assets/videos/splash.mp4'),
nextScreen: HomeScreen(),
backgroundColor: Colors.black,
),
);
}
}
Usage Examples
Auto-Navigation
Video plays and automatically navigates to the next screen:
SplashVideo(
source: AssetSource('assets/videos/splash.mp4'),
nextScreen: HomeScreen(),
backgroundColor: Colors.black,
)
Manual Control
Use a callback for custom logic after video completes:
SplashVideo(
source: AssetSource('assets/videos/splash.mp4'),
onVideoComplete: () {
// Custom logic
// ...
// ...
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (_) => HomeScreen()),
);
},
)
Looping Video with Controller
Create an infinite loop that the user can manually exit:
class MyScreen extends StatefulWidget {
@override
State<MyScreen> createState() => _MyScreenState();
}
class _MyScreenState extends State<MyScreen> {
late final SplashVideoController controller;
@override
void initState() {
super.initState();
controller = SplashVideoController(loopVideo: true);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
void _onSkip() {
controller.skip();
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (_) => HomeScreen()),
);
}
@override
Widget build(BuildContext context) {
return SplashVideo(
source: AssetSource('assets/videos/splash.mp4'),
controller: controller,
footerWidget: ElevatedButton(
onPressed: _onSkip,
child: Text('Skip'),
),
);
}
}
With Overlays
Add title, footer, and custom overlays:
SplashVideo(
source: AssetSource('assets/videos/splash.mp4'),
nextScreen: HomeScreen(),
backgroundColor: Colors.black,
// Title at top
titleWidget: Padding(
padding: EdgeInsets.all(20),
child: Text(
'Welcome',
style: TextStyle(fontSize: 32, color: Colors.white),
),
),
// Footer at bottom
footerWidget: CircularProgressIndicator(),
// Custom overlay with full control
overlayBuilder: (context) => Positioned(
right: 20,
top: 100,
child: Text('v1.0.0', style: TextStyle(color: Colors.white)),
),
)
Network Video
Load video from URL:
SplashVideo(
source: NetworkFileSource('https://example.com/splash.mp4'),
nextScreen: HomeScreen(),
)
Video Scale Modes
Control how your video fills the screen with 7 different scale modes:
SplashVideo(
source: AssetSource('assets/videos/splash.mp4'),
nextScreen: HomeScreen(),
videoConfig: VideoConfig(
fitMode: VideoFitMode.cover, // Fill screen, may crop edges (best for splash)
),
)
Available Scale Modes:
VideoFitMode.cover- Fill screen, maintain aspect, may crop (recommended for splash screens)VideoFitMode.contain- Fit inside, maintain aspect, may show letterboxingVideoFitMode.fill- Stretch to fill (ignores aspect ratio, may distort)VideoFitMode.fitWidth- Match width, maintain aspectVideoFitMode.fitHeight- Match height, maintain aspectVideoFitMode.scaleDown- Like contain but won't upscale beyond original sizeVideoFitMode.none- Original size, centered
Quick Comparison:
| Fit Mode | Best For | Maintains Aspect | May Crop | May Letterbox |
|---|---|---|---|---|
cover |
Splash screens, hero sections | ✅ | ✅ | ❌ |
contain |
Viewing entire video | ✅ | ❌ | ✅ |
fill |
Exact fill (rare) | ❌ | ❌ | ❌ |
fitWidth |
Horizontal content | ✅ | Vertical | Horizontal |
fitHeight |
Vertical content | ✅ | Horizontal | Vertical |
scaleDown |
Small videos | ✅ | ❌ | ✅ |
none |
Pixel-perfect display | ✅ | ❌ | ✅ |
Custom Configuration
SplashVideo(
source: AssetSource('assets/videos/splash.mp4'),
nextScreen: HomeScreen(),
videoConfig: VideoConfig(
playImmediately: true,
fitMode: VideoFitMode.cover,
useSafeArea: true,
volume: 50.0,
enableAudio: true,
onPlayerInitialized: (player) {
print('Player ready: ${player.state.duration}');
},
),
)
API Reference
SplashVideo
Main widget for video splash screen.
| Parameter | Type | Required | Description |
|---|---|---|---|
source |
Source |
✅ | Video source (Asset, Network, DeviceFile, Bytes) |
controller |
SplashVideoController? |
⚠️ | Required when looping is enabled |
videoConfig |
VideoConfig? |
❌ | Playback configuration |
backgroundColor |
Color? |
❌ | Background color behind video |
titleWidget |
Widget? |
❌ | Widget at top of screen |
footerWidget |
Widget? |
❌ | Widget at bottom of screen |
overlayBuilder |
Widget Function(BuildContext)? |
❌ | Custom overlay builder |
nextScreen |
Widget? |
❌ | Screen to navigate to (auto-navigate) |
onVideoComplete |
VoidCallback? |
❌ | Callback when video completes (manual control) |
onSourceLoaded |
VoidCallback? |
❌ | Callback when video loads |
Validation Rules:
- Cannot use both
nextScreenandonVideoComplete - Looping videos require
controllerand cannot usenextScreenoronVideoComplete
SplashVideoController
Controls video playback.
final controller = SplashVideoController(loopVideo: true);
// Access media_kit Player
controller.player.play();
controller.player.pause();
controller.player.seek(Duration(seconds: 5));
// Controller methods
controller.play();
controller.pause();
controller.skip(); // Complete immediately
controller.dispose();
VideoConfig
Configuration for video playback.
VideoConfig(
playImmediately: true, // Auto-play on load
fitMode: VideoFitMode.cover, // How video fills screen (7 modes)
useSafeArea: false, // Wrap in SafeArea
volume: 80.0, // Volume (0-100), default 80
enableAudio: true, // Enable/disable audio track
hwdec: HwdecMode.autoSafe, // Hardware decode mode (9 modes)
onPlayerInitialized: (player) { },// Player ready callback
)
Parameters:
playImmediately(bool) - Start playing immediately after load. Default:truefitMode(VideoFitMode) - Video sizing strategy. Default:VideoFitMode.coveruseSafeArea(bool) - Avoid notches and system UI. Default:falsevolume(double) - Initial volume 0-100. Default:80.0enableAudio(bool) - Enable audio track (more efficient than volume=0). Default:truehwdec(HwdecMode?) - Hardware decode mode. Default:null(smart platform defaults)onPlayerInitialized(Function?) - Callback when Player is ready
HwdecMode
Hardware decode modes for video playback. When null, smart platform defaults are used:
- Windows:
HwdecMode.autoSafe(avoids CUDA errors on non-NVIDIA systems) - Other platforms:
HwdecMode.auto
// Let the package use smart defaults (recommended)
VideoConfig() // hwdec: null
// Explicit safe mode (recommended for Windows)
VideoConfig(hwdec: HwdecMode.autoSafe)
// Force software decoding
VideoConfig(hwdec: HwdecMode.disabled)
// Platform-specific
VideoConfig(hwdec: HwdecMode.d3d11va) // Windows DirectX 11
VideoConfig(hwdec: HwdecMode.videoToolbox) // macOS/iOS
VideoConfig(hwdec: HwdecMode.vaapi) // Linux
VideoConfig(hwdec: HwdecMode.mediaCodec) // Android
Available Modes:
| Mode | String Value | Description |
|---|---|---|
auto |
"auto" |
Try all methods (may log errors on Windows) |
autoSafe |
"auto-safe" |
Safe methods only (Windows recommended) |
autoCopy |
"auto-copy" |
Auto with memory copy |
disabled |
"no" |
Software decoding only |
d3d11va |
"d3d11va" |
DirectX 11 (Windows) |
dxva2 |
"dxva2" |
DirectX 9 (Windows legacy) |
videoToolbox |
"videotoolbox" |
VideoToolbox (macOS/iOS) |
vaapi |
"vaapi" |
VA-API (Linux) |
mediaCodec |
"mediacodec" |
MediaCodec (Android) |
Source Types
// Asset bundled with app
AssetSource('assets/videos/splash.mp4')
// Network URL
NetworkFileSource('https://example.com/video.mp4')
// Device file
DeviceFileSource('/path/to/video.mp4')
// Raw bytes
BytesSource(videoBytes)
Migration Guide
From v0.0.1 to v0.0.2+
The VideoAspectRatio enum has been replaced with VideoFitMode for better video sizing control:
Old API (Deprecated but still works):
VideoConfig(
videoVisibilityEnum: VideoAspectRatio.useFullScreen,
)
New API (Recommended):
VideoConfig(
fitMode: VideoFitMode.cover,
)
Migration Table:
| Old API | New API | Notes |
|---|---|---|
VideoAspectRatio.useFullScreen |
VideoFitMode.cover |
Now properly fills screen |
VideoAspectRatio.useAspectRatio |
VideoFitMode.contain |
Same behavior |
VideoAspectRatio.none |
VideoFitMode.none |
Same behavior |
videoVisibilityEnum parameter |
fitMode parameter |
Renamed for clarity |
The old API will be removed in v1.0.0. Update your code to use the new fitMode parameter.
Lifecycle Methods
// Defer first frame (prevents jank)
SplashVideo.initialize();
// Resumes frame painting
SplashVideo(
source: AssetSource(Assets.splashVideo),
backgroundColor: Colors.black,
onVideoComplete: () => _videoComplete(),
videoConfig: const VideoConfig(
scale: VideoScaleMode.fill,
useSafeArea: true,
)
);
License
MIT License - see LICENSE file for details.