• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Enabling Picture-in-Picture
2The web component supports the picture-in-picture (PiP) feature. An application can use the Picture-in-Picture API of the W3C standard to create a floating window on a web page to play videos. In this way, users can continue to watch videos in the PiP window when browsing other web pages or interacting with other applications.
3
4To use online video resources, you need to set the network permission in the configuration file. For details about how to add permissions, see [Declaring Permissions in the Configuration File](../security/AccessToken/declare-permissions.md).
5
6```json
7// src/main/module.json5
8"requestPermissions": [
9  {
10    "name": "ohos.permission.INTERNET"
11  },
12]
13```
14
15## Constraints
161. H.264/H.265/HLS videos can be played in the PiP window.
172. The size of the PiP window is adjusted based on the system capability. For details, see the system features and capabilities in the design guide.
18
19## Entering Picture-in-Picture
20
21In the following example, a video element that includes only a media source and a button element for user interaction are used to describe how to create a PiP window, through which a user can continuously watch a video when browsing another web page or interacting with another application.
22
23```html
24<!-- Replace the URL with the actual URL of the video source -->
25<video id="video" src="https://example.com/file.mp4" controls></video>
26<button id="togglePipButton">Enable PiP</button>
27```
28
29Use the **requestPictureInPicture()** method provided by the **HTMLVideoElement** API to enable the PiP feature. If the system supports the PiP feature, the video is displayed in PiP mode.
30
31```js
32togglePipButton.addEventListener("click", async () => {
33  try {
34    // Request to enter the picture-in-picture mode.
35    await video.requestPictureInPicture();
36  } catch (err) {
37    // If the PiP mode fails to be switched, an error message is displayed.
38    console.error("Picture-in-Picture mode failed:", err);
39  }
40});
41```
42
43## Exiting Picture-in-Picture
44
45To exit the PiP mode, use the **exitPictureInPicture()** method of the **Document** API to display the video on the original tab page.
46
47```js
48// ...
49try {
50  if (videoElement !== document.pictureInPictureElement) {
51    await videoElement.requestPictureInPicture();
52  } else {
53    await document.exitPictureInPicture();
54  }
55}
56// ...
57```
58
59## Listening for Picture-in-Picture Events
60
61When a user enables the picture-in-picture mode, a floating window is displayed for playing the video. The system specifies that only one picture-in-picture video can be played at a time.
62When **HTMLVideoElement** successfully enters the PiP mode, the **enterpictureinpicture** event is triggered. When **HTMLVideoElement** successfully exits the PiP mode, the **leavepictureinpicture** event is triggered.
63You can handle these events by listening for them.
64
65
66```js
67videoElement.addEventListener('enterpictureinpicture', function (event) {
68// The video enters the PiP mode.
69});
70
71videoElement.addEventListener('leavepictureinpicture', function (event) {
72// The video exits the PiP mode.
73});
74```
75
76## Interacting with the Picture-in-Picture Window
77
78* PiP window control:
79  Allows users to double-click a PiP window to zoom in or zoom out the window.
80  Allows users to drag the PiP window to any position on the screen.
81  Allows users to click the PiP window to display or hide UI components at the PiP control layer.
82
83* UI components at the PiP control layer:
84  The PiP window control layer includes the close (close the PiP window) and restore (restore from the PiP window to the original application UI) components.
85  The playback control includes the pause, play, and forward/rewind components. (By default, the forward/rewind UI component is displayed. If the original video does not support forward/rewind, there is no response for click events.)
86
87  ![web-picture-in-picture](figures/web-picture-in-picture-ui.png)
88
89
90## Example
91
92The following is an example of entering and exiting the PiP mode:
93
94* ETS code on the application side:
95
96  ```ts
97  // xxx.ets
98  import {webview} from '@kit.ArkWeb';
99
100  @Entry
101  @Component
102  struct Index {
103    @State videoSrc: Resource = $rawfile('PictureInPicture.html')
104
105
106    controller: webview.WebviewController = new webview.WebviewController()
107
108    build() {
109      Column() {
110        Web({src: this.videoSrc, controller: this.controller})
111      }
112    }
113  }
114  ```
115
116* Code of the HTML page:
117
118  ```html
119  <!-- picture-in-picture.html -->
120  <!DOCTYPE html>
121  <html lang="en">
122  <head>
123      <meta charset="UTF-8" />
124      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
125      <title>Picture-in-Picture Demo</title>
126      <style>
127          body {
128            font-family: Arial, sans-serif;
129            display: flex;
130            flex-direction: column;
131            align-items: center;
132            justify-content: center;
133            height: 100vh;
134            margin: 0;
135          }
136          video {
137            width: 60%;
138            border: 1px solid #ccc;
139            border-radius: 8px;
140            margin-bottom: 20px;
141          }
142          button {
143            padding: 10px 20px;
144            font-size: 16px;
145            cursor: pointer;
146          }
147      </style>
148  </head>
149  <body>
150  <!-- Replace the URL with the actual URL of the video source -->
151  <video id="video" src="https://example.com/file.mp4" controls></video>
152  <button id="togglePipButton">Enable PiP</button>
153
154  <script>
155      const video = document.getElementById("video");
156      const togglePipButton = document.getElementById("togglePipButton");
157
158      // If the browser does not support the PiP feature or the feature is disabled, the button is hidden.
159      togglePipButton.hidden =
160        !document.pictureInPictureEnabled || video.disablePictureInPicture;
161
162      // Listen for the click events to enter or exit the PiP mode.
163      togglePipButton.addEventListener("click", async () => {
164        try {
165          if (document.pictureInPictureElement) {
166            // If the PiP mode is used, exit the PiP mode.
167            await document.exitPictureInPicture();
168          } else {
169            // Otherwise, enter the PiP mode.
170            await video.requestPictureInPicture();
171          }
172        } catch (err) {
173          // If the PiP mode fails to be switched, an error message is displayed.
174          console.error("Picture-in-Picture mode failed:", err);
175        }
176      });
177
178      // Listen for the PiP enter event.
179      video.addEventListener("enterpictureinpicture", () => {
180        // Update the button text to "Exit PiP"
181        togglePipButton.textContent = "Exit PiP"
182      });
183
184      // Listen for the PiP exit event.
185      video.addEventListener("leavepictureinpicture", () => {
186        // Update the button text to "Enable PiP"
187        togglePipButton.textContent = "Enable PiP"
188      });
189  </script>
190  </body>
191  </html>
192  ```
193