Thiết lập ứng dụng để dùng tính năng PiP (Hình trong hình)

Trong thẻ hoạt động của tệp AndroidManifest.xml, hãy làm như sau:

  1. Thêm supportsPictureInPicture và đặt thành true để khai báo rằng bạn sẽ sử dụng chế độ hình trong hình (PiP) trong ứng dụng.
  2. Thêm configChanges và đặt thành orientation|screenLayout|screenSize|smallestScreenSize để chỉ định rằng hoạt động của bạn xử lý các thay đổi về cấu hình bố cục. Bằng cách này, hoạt động của bạn sẽ không chạy lại khi các thay đổi về bố cục xảy ra trong quá trình chuyển đổi chế độ PiP.
<activity
    android:name=".SnippetsActivity"
    android:exported="true"
    android:supportsPictureInPicture="true"
    android:configChanges="orientation|screenLayout|screenSize|smallestScreenSize"
    android:theme="@style/Theme.Snippets">

Trong mã Compose, hãy làm như sau:

  1. Thêm tiện ích này vào Context. Bạn sẽ sử dụng tiện ích này nhiều lần trong suốt hướng dẫn để truy cập vào hoạt động.
    internal fun Context.findActivity(): ComponentActivity {
        var context = this
        while (context is ContextWrapper) {
            if (context is ComponentActivity) return context
            context = context.baseContext
        }
        throw IllegalStateException("Picture in picture should be called in the context of an Activity")
    }

Thêm chế độ PiP khi rời khỏi ứng dụng cho các phiên bản trước Android 12

Để thêm chế độ PiP cho các phiên bản Android trước 12, hãy dùng addOnUserLeaveHintProvider. Làm theo các bước sau để thêm chế độ PiP cho các phiên bản trước Android 12:

  1. Thêm một cổng phiên bản để chỉ truy cập vào mã này trong các phiên bản từ O đến R.
  2. Dùng DisposableEffect với Context làm khoá.
  3. Bên trong DisposableEffect, hãy xác định hành vi khi onUserLeaveHintProvider được kích hoạt bằng cách sử dụng một lambda. Trong hàm lambda, hãy gọi enterPictureInPictureMode() trên findActivity() rồi truyền vào PictureInPictureParams.Builder().build().
  4. Thêm addOnUserLeaveHintListener bằng cách sử dụng findActivity() và truyền vào lambda.
  5. Trong onDispose, hãy thêm removeOnUserLeaveHintListener bằng cách sử dụng findActivity() và truyền vào hàm lambda.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
    Build.VERSION.SDK_INT < Build.VERSION_CODES.S
) {
    val context = LocalContext.current
    DisposableEffect(context) {
        val onUserLeaveBehavior = Runnable {
            context.findActivity()
                .enterPictureInPictureMode(PictureInPictureParams.Builder().build())
        }
        context.findActivity().addOnUserLeaveHintListener(
            onUserLeaveBehavior
        )
        onDispose {
            context.findActivity().removeOnUserLeaveHintListener(
                onUserLeaveBehavior
            )
        }
    }
} else {
    Log.i("PiP info", "API does not support PiP")
}

Thêm chế độ PiP khi rời khỏi ứng dụng cho các thiết bị sau Android 12

Sau Android 12, PictureInPictureParams.Builder sẽ được thêm thông qua một đối tượng sửa đổi được truyền đến trình phát video của ứng dụng.

  1. Tạo một modifier rồi gọi onGloballyPositioned trên modifier đó. Toạ độ bố cục sẽ được dùng ở bước sau.
  2. Tạo một biến cho PictureInPictureParams.Builder().
  3. Thêm câu lệnh if để kiểm tra xem SDK có phải là S trở lên hay không. Nếu có, hãy thêm setAutoEnterEnabled vào trình tạo và đặt thành true để chuyển sang chế độ PiP khi vuốt. Điều này giúp ảnh động mượt mà hơn so với việc chuyển đổi thông qua enterPictureInPictureMode.
  4. Gọi setPictureInPictureParams() bằng findActivity(). Gọi build() trên builder rồi truyền vào.

val pipModifier = modifier.onGloballyPositioned { layoutCoordinates ->
    val builder = PictureInPictureParams.Builder()

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        builder.setAutoEnterEnabled(true)
    }
    context.findActivity().setPictureInPictureParams(builder.build())
}
VideoPlayer(pipModifier)

Dùng biểu tượng setAspectRatio để đặt tỷ lệ khung hình cho cửa sổ PiP

Để đặt tỷ lệ khung hình cho cửa sổ PiP, bạn có thể chọn một tỷ lệ khung hình cụ thể hoặc sử dụng chiều rộng và chiều cao của kích thước video trong trình phát. Nếu bạn đang sử dụng trình phát media3, hãy kiểm tra để đảm bảo trình phát không có giá trị rỗng và kích thước video của trình phát không bằng VideoSize.UNKNOWN trước khi đặt tỷ lệ khung hình.

val context = LocalContext.current

val pipModifier = modifier.onGloballyPositioned { layoutCoordinates ->
    val builder = PictureInPictureParams.Builder()
    if (shouldEnterPipMode && player != null && player.videoSize != VideoSize.UNKNOWN) {
        val sourceRect = layoutCoordinates.boundsInWindow().toAndroidRectF().toRect()
        builder.setSourceRectHint(sourceRect)
        builder.setAspectRatio(
            Rational(player.videoSize.width, player.videoSize.height)
        )
    }

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        builder.setAutoEnterEnabled(shouldEnterPipMode)
    }
    context.findActivity().setPictureInPictureParams(builder.build())
}

VideoPlayer(pipModifier)

Nếu bạn đang sử dụng một trình phát tuỳ chỉnh, hãy đặt tỷ lệ khung hình theo chiều cao và chiều rộng của trình phát bằng cú pháp dành riêng cho trình phát của bạn. Xin lưu ý rằng nếu trình phát của bạn đổi kích thước trong quá trình khởi tạo, nếu kích thước đó nằm ngoài phạm vi hợp lệ của tỷ lệ khung hình, thì ứng dụng của bạn sẽ gặp sự cố. Bạn có thể cần thêm các bước kiểm tra về thời điểm có thể tính toán tỷ lệ khung hình, tương tự như cách thực hiện đối với trình phát media3.