日本熟妇hd丰满老熟妇,中文字幕一区二区三区在线不卡 ,亚洲成片在线观看,免费女同在线一区二区

如何實現懸浮窗和畫中畫功能

您可以在應用層調用播放器SDK,結合系統API實現懸浮窗、畫中畫播放功能。本文為您介紹如何在Android和iOS平臺上實現播放器SDK的懸浮窗、畫中畫播放功能。

Android技術方案

Android系統提供了多種不同的方案供您選擇,包括懸浮窗、畫中畫方案,例如電商場景下常見的浮窗方案。此處僅介紹常見的實現方法。

懸浮窗

懸浮窗是Android系統中的一種浮動窗口,可以在其他應用程序的上層顯示。它可以進行隨意拖動、縮放、關閉等操作,通常用于提醒、通知和廣告。

  • 在Android系統中,每個窗口都對應一個Window對象,而懸浮窗就是一種特殊的Window,通常情況下,懸浮窗可以通過ViewSystem中的PopupWindow來實現。

  • 其中,PopupWindow是繼承自具有運動能力的WindowManager.LayoutParams的一個類,因此可以對其進行位置、大小和顯示方式等操作。同時,可以使用PopupWindow實現一個自定義懸浮窗,而不影響其他應用,并且無需通過Activity跳轉。

實現步驟如下:

  1. 在AndroidManifest.xml中聲明懸浮窗權限。

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
  2. 在需要顯示懸浮窗的Activity或Service中,通過創建WindowManager和PopupWindow,設置其顯示位置、大小和內容等屬性。

    //創建布局
    View layout = View.inflate(this, R.layout.float_window, null);
    //創建管理器
    WindowManager wm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
    //創建懸浮窗
    PopupWindow mPopupWindow = new PopupWindow(layout,
                                               WindowManager.LayoutParams.WRAP_CONTENT,
                                               WindowManager.LayoutParams.WRAP_CONTENT);
    //設置顯示位置
    mPopupWindow.showAtLocation(parentView, Gravity.LEFT | Gravity.TOP, x, y);
    //設置可點擊和可獲取焦點
    mPopupWindow.setTouchable(true);
    mPopupWindow.setFocusable(true);
    //設置背景色
    mPopupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
  3. 設置懸浮窗布局內控件的點擊事件、拖拽監聽事件等。

    mPopupWindow.setOnTouchListener(new View.OnTouchListener() {
        int lastX, lastY;
        int paramX, paramY;
    
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            //獲取當前觸摸點相對于屏幕的坐標
            int x = (int) event.getRawX();
            int y = (int) event.getRawY();
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    lastX = x;
                    lastY = y;
                    paramX = mPopupWindow.getLayoutParams().x;
                    paramY = mPopupWindow.getLayoutParams().y;
                    break;
                case MotionEvent.ACTION_MOVE:
                    int dx = x - lastX;
                    int dy = y - lastY;
                    mPopupWindow.update(paramX + dx, paramY + dy, -1, -1);
                    break;
            }
            return false;
        }
    });
    重要

    在Android 6.0及以上版本中,需要動態申請懸浮窗權限。然而,即使如此,在某些Android 8.0手機上,仍然不支持此功能。

畫中畫

  • 從Android 8.0(API 26)開始,Android引入了畫中畫(PiP)模式啟動Activity的功能。畫中畫是一種特殊類型的多窗口模式,最常用于視頻播放。在該模式下,用戶可以將視頻以小窗口的形式固定在屏幕的一角,同時在應用之間進行導航或瀏覽主屏幕上的內容。

  • 畫中畫利用Android 7.0中提供的多窗口模式API來實現固定的視頻疊加窗口。為了在應用中添加畫中畫功能,您需要注冊支持畫中畫的Activity,并根據需要將該Activity切換為畫中畫模式,同時,確保當Activity處于畫中畫模式時,界面元素處于隱藏狀態且視頻能夠繼續播放。

  • 畫中畫窗口會顯示在屏幕的最上層,通常位于系統選擇的一角。

  • 有關Android系統對畫中畫功能的支持情況請參見:Android · 對畫中畫 (PiP) 的支持

實現步驟如下:

  1. 在AndroidManifest.xml中聲明Activity對畫中畫的支持。

    <Activity android:name="VideoActivity"
      android:supportsPictureInPicture="true"
      android:configChanges=
      "screenSize|smallestScreenSize|screenLayout|orientation"
      ...
    • 默認情況下,Android系統不會自動為應用提供畫中畫功能的支持。如果您想在應用中支持畫中畫功能,可以在AndroidManifest.xml清單文件中注冊視頻Activity,并將android:supportsPictureInPicture屬性設置為true。

    • 另外,在注冊支持畫中畫的Activity時,還需要指定該Activity來處理布局配置更改。這樣,在畫中畫模式切換期間,如果出現布局更改,您的Activity將不會重新啟動,從而提供更加流暢的用戶體驗。

      重要

      低RAM設備可能無法使用畫中畫模式。在應用使用畫中畫之前,請務必通過調用hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)進行檢查,以確保可以使用畫中畫。

  2. 將Activity切換到畫中畫模式。

    進入PIP模式的最常見流程如下:

    • 從按鈕觸發(例如通過點擊按鈕)

      onClicked(View),onOptionsItemSelected(MenuItem) 等等。

      @Override
      public void onActionClicked(Action action) {
          if (action.getId() == R.id.lb_control_picture_in_picture) {
          	// 從按鈕觸發
              enterPictureInPictureMode();
              return;
          }
          ...
      }
    • 有意的離開您的應用程序觸發(例如通過按下Home鍵)

      onUserLeaveHint()

      如要進入畫中畫模式,Activity必須調用enterPictureInPictureMode()。在用戶按下主屏幕或最近使用的應用按鈕時,可以通過替換onUserLeaveHint()來實現應用自動切換到畫中畫模式。

      @Override
      public void onUserLeaveHint () {
          // 有意的離開您的應用程序觸發
          if (iWantToBeInPipModeNow()) {
              enterPictureInPictureMode();
          }
      }
    • 從返回觸發(例如通過按下返回按鈕)

      onBackPressed()

      @Override
      public void onBackPressed() {
          super.onBackPressed();
          // 從返回觸發
          enterPictureInPictureMode();
      }
  3. 處理畫中畫模式下的界面元素。

    當Activity進入或退出畫中畫模式時,系統會調用Activity.onPictureInPictureModeChanged()方法或Fragment.onPictureInPictureModeChanged()方法。

    您應替換這些回調以重新繪制Activity的界面元素。請注意,在畫中畫模式下,Activity會以一個小窗口的形式顯示,用戶無法與應用的界面元素進行互動,并且可能難以看清小窗口中的詳細信息。界面極簡的視頻播放Activity可提供最佳的用戶體驗。

    1. 退出畫中畫模式時支持更流暢的動畫。

      當Activity退出畫中畫模式時,您可以為界面元素添加退出動畫,以提升過渡的流暢性和視覺效果。

    2. 添加控件。

      在畫中畫模式下,用戶可能無法與應用的界面元素進行互動。因此,您可以考慮在畫中畫窗口中添加一些簡單的控件,以便用戶可以進行基本的操作,如播放/暫停、上/下一集等。

    3. 為非視頻內容停用無縫大小調整。

      在畫中畫模式下,視頻內容通常需要保持適當的大小比例,不被拉伸或裁剪。然而,對于非視頻內容,如文本、圖像等,可能需要禁用無縫大小調整,以避免內容在小窗口中變得不可讀或失真。通過禁用無縫大小調整,可以確保非視頻內容在畫中畫模式下保持良好的可見性和可操作性。

  4. 在畫中畫模式下繼續播放視頻。

    當Activity切換到畫中畫模式時,系統會將該Activity置于暫停狀態并調用Activity的onPause()方法。然而,在畫中畫模式下,視頻播放應該繼續進行,而不是暫停。

    在Android 7.0及更高版本中

    • 當系統調用Activity的onStop()時,您應暫停視頻播放。

    • 當系統調用Activity的onStart()時,您應恢復視頻播放。

    這樣,您就無需在onPause()方法中檢查應用是否處于畫中畫模式,只需繼續播放視頻即可。

    如果您必須在onPause()方法中暫停視頻播放,請通過調用isInPictureInPictureMode()方法來檢查是否處于畫中畫模式,并根據需要相應地處理播放狀態。以下是一個示例代碼:

    @Override
    public void onPause() {
        // If called while in PiP mode, do not pause playback
        if (isInPictureInPictureMode()) {
            // Continue playback
            ...
        } else {
            // Use existing playback logic for paused Activity behavior.
            ...
        }
    }

iOS技術方案

目前有三種方式可以實現畫中畫功能:

  1. WKWebView自帶

    如果您在應用中使用了WKWebView進行視頻播放,它已經內置了畫中畫功能。

  2. 使用AVPlayerViewController

    如果對播放器的要求不是很高,可以直接使用AVPlayerViewController。它已經提供了畫中畫功能,只需設置allowsPictureInPicturePlayback屬性為YES,即可在播放器界面上展示畫中畫按鈕。

  3. 自定義播放器并使用AVPictureInPictureController包裝

    如果您使用自定義的播放器,并希望開啟畫中畫功能,可以使用AVPictureInPictureController對播放器進行包裝,簡單易用地實現畫中畫功能,并且AVPictureInPictureController內部已經實現了動畫效果。只需注意用戶需要自己實現畫中畫按鈕,系統已提供了相關API(pictureInPictureButtonStartImage)來使用畫中畫圖標。

懸浮窗

簡單理解為,可以利用UIWindow類型創建一個新的窗口,并將視頻播放器的視圖添加到該窗口上,通過手勢控制窗口的位置和大小,實現懸浮的畫中畫效果。

重要

在iOS的設計準則中,明確規定了不允許在應用程序中使用懸浮窗。使用懸浮窗可能會被蘋果拒絕審核或被迫下架。同時也要考慮到用戶體驗和隱私保護問題,因此在使用懸浮窗時需要謹慎考慮。

畫中畫

畫中畫(Picture-in-Picture)功能在iOS 9版本就已經推出,但在之前的版本中,該功能只能在iPad上使用。直到iOS 14版本,iPhone用戶才能開始使用畫中畫功能。

畫中畫功能在iOS上有兩種實現方案:

  1. 支持iOS 14以上版本的老方案。

    image

    在iOS 14系統中,通過使用系統提供的AVPlayer來初始化AVPictureInPictureController, 進而實現在應用程序壓后臺或進入二級頁面時出現畫中畫效果。這種方案適用于對播放器要求不太高的場景。

  2. 支持iOS 15版本以上的新方案。

    image

    在iOS 15及更高版本中,可以使用SamplebufferLayer來創建AVPictureInPictureController,以實現無縫的畫中畫播放。這種方案通常用于自定義播放器來實現畫中畫功能。目前,阿里云播放器SDK已提供畫中畫功能,操作詳情請參見畫中畫

實現步驟如下:

iOS 15與iOS 14方案實現基本類似,本文以iOS 14老方案為例:

  1. 開啟后臺模式

    image

  2. 導入框架#import <AVKit/AVKit.h>創建AVPictureInPictureController。

    //1.判斷是否支持畫中畫功能
    if ([AVPictureInPictureController isPictureInPictureSupported]) {
        //2.開啟權限
        @try {
            NSError *error = nil;
            [[AVAudioSession sharedInstance] setCategory:AVAudioSessionOrientationBack error:&error];
            [[AVAudioSession sharedInstance] setActive:YES error:&error];
        } @catch (NSException *exception) {
            NSLog(@"AVAudioSession發生錯誤");
        }
        self.pipVC = [[AVPictureInPictureController alloc] initWithPlayerLayer:self.player];
        self.pipVC.delegate = self;
    }
  3. 開啟或關閉畫中畫。

    if (self.pipVC.isPictureInPictureActive) {
        [self.pipVC stopPictureInPicture];
    } else {
        [self.pipVC startPictureInPicture];
    }
  4. 代理AVPictureInPictureControllerDelegate。

    // 即將開啟畫中畫
    - (void)pictureInPictureControllerWillStartPictureInPicture:(AVPictureInPictureController *)pictureInPictureController;
    // 已經開啟畫中畫
    - (void)pictureInPictureControllerDidStartPictureInPicture:(AVPictureInPictureController *)pictureInPictureController;
    // 開啟畫中畫失敗
    - (void)pictureInPictureController:(AVPictureInPictureController *)pictureInPictureController failedToStartPictureInPictureWithError:(NSError *)error;
    // 即將關閉畫中畫
    - (void)pictureInPictureControllerWillStopPictureInPicture:(AVPictureInPictureController *)pictureInPictureController;
    // 已經關閉畫中畫
    - (void)pictureInPictureControllerDidStopPictureInPicture:(AVPictureInPictureController *)pictureInPictureController;
    // 關閉畫中畫且恢復播放界面
    - (void)pictureInPictureController:(AVPictureInPictureController *)pictureInPictureController restoreUserInterfaceForPictureInPictureStopWithCompletionHandler:(void (^)(BOOL restored))completionHandler;
    重要
    1. 通過一個全局變量持有畫中畫控制器,可以在pictureInPictureControllerWillStartPictureInPicture持有,在pictureInPictureControllerDidStopPictureInPicture釋放;

    2. 有時可能不是通過點擊畫中畫按鈕,而是通過其他途徑來打開當前的畫中畫控制器。可以在viewWillAppear方法中進行判斷并關閉。

    3. 在已經存在畫中畫的情況下,若要開啟新的畫中畫,需等待完全關閉之后再進行新的開啟,以防止出現未知錯誤,因為關閉畫中畫是一個有過程的操作。

    4. 在創建AVPictureInPictureController并同時開啟畫中畫功能時,可能會出現失效的情況。如果遇到這種情況,建議延遲開啟畫中畫功能即可。