Implementing Picture-in-Picture in Flutter: Enhancing Video Playback Experience With Auto Enable When Minimized.

Ashish Sharma
Nerd For Tech
Published in
5 min readJan 9, 2024

Imagine this: You’re watching a super cool Marvel movie on your favorite video streaming app when suddenly, your best friend texts you about an awesome weekend plan. Yikes! But what if I told you there’s a way to keep watching your video and chat with your friend at the same time? That’s where Picture-in-Picture (PiP) mode swoops in to save the day! PiP shrinks your video into a mini window, so you can keep watching while checking your messages, scrolling through other stuff, or just being your multitasking superstar self.

So, Let’s dive into PiP and make multitasking fun!

So, What is Picture-in-Picture Mode ?

Picture-in-Picture (PiP) functionality enriches the user experience by allowing video content to be displayed in a resizable and movable window while concurrently using other applications. Implementing PiP in Flutter applications provides users with added flexibility and convenience during video playback or any other functionality.

Why Implement Picture-in-Picture ?

  1. Enhanced Multitasking: PiP enables users to multitask effortlessly by allowing video content to play in a small overlay window while navigating through the app or performing other tasks.
  2. Improved Engagement: PiP encourages longer engagement with video content by providing flexibility in viewing, thereby increasing user retention and satisfaction.
  3. Flexibility and Convenience: The resizable and movable PiP window allows users to adjust the video playback according to their preferences, providing a personalized viewing experience.
  4. Modern and User-Centric Design: Implementing PiP aligns your app with contemporary design trends, demonstrating responsiveness to user needs and preferences.

Now, let’s move to the eagerly awaited moment!

Step 1: Add these packages in your pubspec.yaml

Step 2: Add android:supportsPictureInPicture="true" line to the <activity> tag in android/src/main/AndroidManifest.xml:

<manifest>
<uses-permission android:name="android.permission.INTERNET"/>

<application>
<activity
android:name=".MainActivity"
android:supportsPictureInPicture="true"
...

Step 3: Create a straightforward video player widget with a seek Bar to enable video playback.

Step 4:

The Floating package offers a convenient “PiPSwitcher” widget designed for effortlessly toggling between displayed widgets based on the current Picture-in-Picture (PiP) status. Utilize it in the following manner:

Initialize “Floating” instance to enable PiP view.

class PIPExampleApp extends StatefulWidget {
const PIPExampleApp({super.key});

@override
State<PIPExampleApp> createState() => _PIPExampleAppState();
}

class _PIPExampleAppState extends State<PIPExampleApp> {
final String videoUrl = 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4';

late Floating pip; // Initializing a variable to handle PiP functionalities
bool isPipAvailable = false; // Variable to track PiP availability status

@override
void initState() {
pip = Floating(); // Instantiating the "Floating" instance to manage PiP functionality
super.initState();
_checkPiPAvailability(); // Checking the availability of PiP upon initializing the widget
}

// Method to verify the availability of PiP feature asynchronously
_checkPiPAvailability() async {
isPipAvailable = await pip.isPipAvailable; // Checking if PiP mode is available on the device
setState(() {}); // Triggering a UI update based on the PiP availability status
}

@override
Widget build(BuildContext context) {
return PiPSwitcher(
// Widget displayed when PiP is disabled or app is in foreground state
childWhenDisabled: Scaffold(
body: Column(
children: [
VideoPlayerWidget(videoUrl: videoUrl),
Expanded(
child: Center(
child: ElevatedButton(
onPressed: () {
// Enabling PiP mode if available and configuring the aspect ratio for landscape orientation.
if (isPipAvailable) {
pip.enable(aspectRatio: const Rational.landscape()); // Enabling PiP with a landscape aspect ratio
}
},
child: Text(isPipAvailable ? 'Enable PIP' : 'PIP not available'),
),
),
),
],
),
),
// Widget displayed when PiP window is enabled or app is in background state
childWhenEnabled: VideoPlayerWidget(videoUrl: videoUrl),
);
}
}

Step 5: All Done.

Note: Keep an eye on where the video is playing when you switch to PiP mode because the video restarts from the beginning when you switch.

Bonus Tip

When the user minimizes the application, commonly referred to as minimizing the app or switching to the background, the app’s visibility is reduced, and it moves from the foreground to the background state.

This transition to the background state can be utilized to trigger automatic Picture-in-Picture (PiP) mode, facilitating a seamless and enhanced user experience for video playback or continued app interaction while in PiP mode.

Implementation

In Flutter, the WidgetsBindingObserver is a mixin that helps in observing the application's lifecycle events. It's used alongside the app's state to detect when the application is minimized or moved to the background on the device. This mixin allows developers to monitor these state changes and execute specific actions or manage functionalities accordingly.

class _PIPExampleAppState extends State<PIPExampleApp> with WidgetsBindingObserver {
final String videoUrl = 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4';
late Floating pip; // Instance to handle PiP functionality
bool isPipAvailable = false; // Variable to track PiP availability

@override
void didChangeAppLifecycleState(AppLifecycleState state) {

// Listening to app lifecycle changes to detect when the app enters the hidden state (minimized)
if (state == AppLifecycleState.hidden && isPipAvailable) {

// Triggering PiP mode with a landscape aspect ratio when the app is minimized
pip.enable(aspectRatio: const Rational.landscape());
}
}

...

Full Code

Conclusion

In summary, implementing Picture-in-Picture (PiP) mode in Flutter applications offers a convenient way for users to multitask, allowing them to continue watching videos or accessing specific app features even when the app is minimized or running in the background. By employing techniques like utilizing WidgetsBindingObserver and monitoring the app's lifecycle, developers can seamlessly enable PiP mode, ensuring a smooth and uninterrupted user experience. This feature enhances the app's versatility and user-friendliness, catering to modern user expectations for seamless multitasking and continued engagement.

That’s it for this article! I hope you enjoyed it and leave a few claps if you did. Follow me for more Flutter articles and comment for any feedback you might have about this article.

I‘m Ashish Sharma aka theFlutterist. You can find me on LinkedIn or maybe follow me on GitHub as well.

--

--

Ashish Sharma
Nerd For Tech

TheFlutterist: Teaching Flutter in the most playful way possible. Join me in the land of widgets and hot reloads! http://flutterist.in/