A Swift Package for draggable floating video and audio players in SwiftUI — Telegram-inspired circular mini-player UX with audio support, seekable progress ring, and full UI customization.
- Video & audio — automatic media type detection by file extension
- Draggable floating window — reposition anywhere on screen
- Circular seekable progress ring — scrub playback by dragging
- Playback controls — play/pause, skip, auto-hiding controls
- Configurable UI — size, colors, shadows, animation presets (
.minimal,.full,.compact) - Clean architecture — protocols, delegates, factory pattern, SPM modules
- Performance helpers — debouncing, safe SwiftUI animations, audio session utilities
- Unit tests — configuration and factory coverage
- iOS 16.0+ / macOS 13.0+
- Xcode 15.0+
- Swift 5.9+
| Feature | iOS | macOS |
|---|---|---|
| Floating video player | ✅ | ✅ |
| Floating audio player | ✅ | ✅ |
| Remote video URLs (HTTPS) | ✅ | ✅ |
| Remote audio URLs | ❌ | ❌ |
| Picture-in-Picture | ✅ | — |
Remote audio requires a local file — AVAudioPlayer does not support streaming URLs.
dependencies: [
.package(url: "https://github.com/gromozekapp/FloatingMediaPlayer.git", from: "1.3.5")
]Then add FloatingMediaPlayer to your target dependencies.
import FloatingMediaPlayer
import SwiftUI
struct ContentView: View {
let mediaURL: URL
var body: some View {
YourContent()
.overlay {
FloatingVideoPlayerView(mediaURL: mediaURL)
}
}
}let config = FloatingPlayerConfiguration(
defaultPosition: CGPoint(x: 200, y: 400),
defaultSize: 120,
showControls: true,
borderColor: .blue,
allowDragging: true
)
FloatingVideoPlayerView(mediaURL: mediaURL, configuration: config)final class PlayerEvents: MediaPlayerDelegate {
func mediaPlayerDidStartPlaying(_ player: MediaPlayerProtocol) {
print("Playback started")
}
func mediaPlayerDidFinishPlaying(_ player: MediaPlayerProtocol) {
print("Playback finished")
}
func mediaPlayerDidChangePosition(_ player: MediaPlayerProtocol, position: CGPoint) {}
func mediaPlayerDidChangeSize(_ player: MediaPlayerProtocol, size: CGFloat) {}
func mediaPlayer(_ player: MediaPlayerProtocol, didEncounterError error: Error) {
print("Error: \(error.localizedDescription)")
}
}
struct ContentView: View {
let mediaURL: URL
@State private var playerEvents = PlayerEvents()
var body: some View {
YourContent()
.overlay {
FloatingVideoPlayerView(
mediaURL: mediaURL,
configuration: .full,
delegate: playerEvents
)
}
}
}FloatingVideoPlayerView(mediaURL: mediaURL, configuration: .minimal)
FloatingVideoPlayerView(mediaURL: mediaURL, configuration: .full)
FloatingVideoPlayerView(mediaURL: mediaURL, configuration: .compact)See FloatingPlayerConfiguration for position, size, controls timeout, drag behavior, colors, and shadows.
Video: MP4, MOV, AVI, MKV, M4V, 3GP, WebM
Audio: MP3, M4A, WAV, AAC, FLAC, OGG
| Type | Purpose |
|---|---|
FloatingVideoPlayerView |
Main SwiftUI floating player view |
FloatingPlayerConfiguration |
UI and behavior configuration |
MediaPlayerDelegate |
Playback and interaction events |
MediaPlayerFactory |
Creates video/audio players by URL |
MediaPlayerProtocol |
Shared player interface |
let debouncedUpdate = PerformanceUtils.debounce(delay: 0.3) { value in
updatePlayerPosition(value)
}
AnimationUtils.safeAnimation(.spring()) {
playerSize = newSize
}swift testOpen Examples/FMP_EXAMPLE/FMP_EXAMPLE.xcodeproj in Xcode and run on an iOS Simulator or device.
The sample app includes:
- File and photo pickers
- Basic, custom configuration, and preset tabs
- Delegate event logging
See Docs/README.md for recording instructions.
GitHub release notes for v1.3.5: Docs/RELEASE_NOTES_v1.3.5.md
- Subtitles support
- Keyboard shortcuts
- Playlists
- Custom themes
See CHANGELOG.md for release history.
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Run
swift test - Open a Pull Request
MIT — see LICENSE.
