CompactOverlay mode - aka Picture-in-Picture

Note: The new feature(s) covered in this post are available to Windows Insiders running build 15021 or newer.

New in Creators Update: In the most recent Windows 10 Creators Update we introduce a new compact overlay mode for UWA app windows. When an app window enters compact overlay mode it’ll be shown above other windows so it won’t get blocked. This allows users to continue to keep an eye on your app's content even when they are working with something else. The canonical example of an app taking advantage of this feature is a media player or a video chat app.
CompactOverlay feature used to create a picture-in-picture media player experience

Quick Summary

The ViewMode APIs that powers the CompactOverlay mode described in this blogpost have three parts:

  • the ability to check if CompactOverlay mode is available to the app at all
  • the ability to transition an existing view in and out of CompactOverlay mode
  • the ability to show a standalone view in CompactOverlay mode.

If you're not familiar with multiple views, just skip that part of this blogpost for now or go explore the MultipleViews github sample then come back for that part.

The basics

For a single view app, which most UWP apps are, adding a compact overlay option to the app is easy and straight forward. First you put in some kind of UX affordance that lets the user switch modes (since this is a sample we go with a button), check if the view mode we want to enable is available (if so, make the button visible) and then change the view mode when the user taps on the UX affordance.

Is CompactOverlay supported?

Since the intent of the Compact Overlay view mode is a very specific type of user experience, it is not necessarily supported across all Windows devices and interaction modes. Best practice for the app developer is therefore to check whether it is supported before enabling the UX affordance in the app that lets users access this functionality.

 if (ApplicationView.GetForCurrentView().IsViewModeSupported(ApplicationViewMode.CompactOverlay))
{
    compactOverlayButton.Visibility = Visibility.Visible;
}

Switching the view into CompactOverlay mode

At its core the CompactOverlay API is really about this one function call:

 private async void compactOverlayButton_Click(object sender, RoutedEventArgs e)
{
    bool modeSwitched = await ApplicationView.GetForCurrentView().TryEnterViewModeAsync(ApplicationViewMode.CompactOverlay);
}

This API operates on the current ApplicationView of the app, transitioning it from one view mode into another, which in this case is from the default view mode into CompactOverlay mode. When this happens you will note some attributes changing for the window:

  1. it will most likely become smaller than your app window was prior to the call
  2. it will be moved to the top-right corner area of the screen
  3. if you move focus away from the CompactOverlay window the title bar will disappear

To get back to your normal app layout window just call the same API again, but this time with a ApplicationViewMode.Default:

 private async void standardModeButton_Click(object sender, RoutedEventArgs e)
{
    bool modeSwitched = await ApplicationView.GetForCurrentView().TryEnterViewModeAsync(ApplicationViewMode.Default);
}

This will restore your application view to the size and position it had before going into CompactOverlay mode and you can navigate the user back to the app's main layout again.

Providing options for the view

When going into CompactOverlay you probably have a very specific experience in mind for the user, such as providing a mini-view of a video chat, or a certain scaled down version of a video where you want to make sure it can maintains its aspect ratio in the new view configuration.

To enable this we give you the ability to provide a ViewModePreferences object when calling the API. At the time of this post the only preference you can set that will be considered by the system when displaying your view is the CustomSize property which allows you to set the size of the view as it switches into the new mode.

ViewModePreference works a little different then other preference objects that you may have worked with in the windowing space before in that you have to create a default version of it for the mode you want and then then modify the object you get back, instead of just calling 'new' and setting all the preferences to the correct values. The reason for this is that we want to make sure that future additions to the object gets set properly for the mode you are modifying and that vital preferences are not missed as the bells'n'whistles of this API are extended.

If we wanted to set the window size to 320x200 when switching into CompactOverlay the code looks like this:

 private async void compactOverlayButton_Click(object sender, RoutedEventArgs e)
{
    ViewModePreferences compactOptions = ViewModePreferences.CreateDefault(ApplicationViewMode.CompactOverlay);
    compactOptions.CustomSize = new Windows.Foundation.Size(320, 200);
    bool modeSwitched = await ApplicationView.GetForCurrentView().TryEnterViewModeAsync(ApplicationViewMode.Default, compactOptions);
}

Working with a separate view for CompactOverlay

As mentioned in the introduction you can also have new views show up as CompactOverlay views while your main app view remains untouched. The principle for this is the same as with multiview apps but we have added a new switcher API for transitioning the view directly into the specified mode as it is shown so that you avoid the flicker that would be the result of first showing the view as standalone (using TryShowAsStandaloneAsync) and then calling TryEnterViewMode on it.

The switcher API follows the same pattern as the API that acts on the current view, where you provide the mode you want to switch into and, if needed, the preferences for the view. In its most simple form the call would look like this:

 private async void ShowCompactView()
{
    await CoreApplication.CreateNewView().Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
    {
        var frame = new Frame();
        compactViewId = ApplicationView.GetForCurrentView().Id;
        frame.Navigate(typeof(SecondaryCompactViewPage));
        Window.Current.Content = frame;
        Window.Current.Activate();
        ApplicationView.GetForCurrentView().Title = "CompactOverlay Window";
    });
    bool viewShown = await ApplicationViewSwitcher.TryShowAsViewModeAsync(compactViewId, ApplicationViewMode.CompactOverlay);
}

You can of course also set the preferred size of your pop-out window just as you did with the TryEnterViewMode, just add the ViewModePreferences to the TryShowAsViewModeAsync call and you're done!

For more details on how to work with CreateNewView, view switching APIs in general, and best practices for view lifetime control - please refer to the MultipleViews github sample.