ตั้งค่าแอปสำหรับ PIP

ในแท็กกิจกรรมของไฟล์ AndroidManifest.xml ให้ทำดังนี้

  1. เพิ่ม supportsPictureInPicture และตั้งค่าเป็น true เพื่อประกาศว่าคุณจะใช้การแสดงภาพซ้อนภาพ (PIP) ในแอป
  2. เพิ่ม configChanges และตั้งค่าเป็น orientation|screenLayout|screenSize|smallestScreenSize เพื่อระบุว่ากิจกรรมของคุณจัดการการเปลี่ยนแปลงการกำหนดค่าเลย์เอาต์ วิธีนี้จะช่วยให้กิจกรรมไม่เปิดขึ้นมาอีกครั้งเมื่อมีการเปลี่ยนแปลงเลย์เอาต์ระหว่างการเปลี่ยนโหมด PiP
<activity
    android:name=".SnippetsActivity"
    android:exported="true"
    android:supportsPictureInPicture="true"
    android:configChanges="orientation|screenLayout|screenSize|smallestScreenSize"
    android:theme="@style/Theme.Snippets">

ในโค้ด Compose ให้ทำดังนี้

  1. เพิ่มส่วนขยายนี้ใน Context คุณจะใช้ส่วนขยายนี้หลายครั้งตลอดทั้งคู่มือเพื่อเข้าถึงกิจกรรม
    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")
    }

เพิ่ม PiP เมื่อออกจากแอปสำหรับ Android เวอร์ชันก่อน 12

หากต้องการเพิ่ม PIP สำหรับ Android เวอร์ชันก่อน 12 ให้ใช้ addOnUserLeaveHintProvider ทำตามขั้นตอนต่อไปนี้เพื่อเพิ่ม PiP สำหรับ Android เวอร์ชันก่อน 12

  1. เพิ่มเกตเวอร์ชันเพื่อให้เข้าถึงโค้ดนี้ได้เฉพาะในเวอร์ชัน O ถึง R เท่านั้น
  2. ใช้ DisposableEffect โดยมี Context เป็นคีย์
  3. ภายใน DisposableEffect ให้กำหนดลักษณะการทำงานเมื่อมีการเรียกใช้ onUserLeaveHintProvider โดยใช้ Lambda ใน Lambda ให้เรียกใช้ enterPictureInPictureMode() ใน findActivity() และส่ง PictureInPictureParams.Builder().build()
  4. เพิ่ม addOnUserLeaveHintListener โดยใช้ findActivity() และส่งใน Lambda
  5. ใน onDispose ให้เพิ่ม removeOnUserLeaveHintListener โดยใช้ findActivity() และส่งใน 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")
}

เพิ่ม PiP เมื่อออกจากแอปสำหรับ Android 12 ขึ้นไป

หลังจาก Android 12 ระบบจะเพิ่ม PictureInPictureParams.Builder ผ่านตัวแก้ไขที่ส่งไปยังวิดีโอเพลเยอร์ของแอป

  1. สร้าง modifier และเรียกใช้ onGloballyPositioned ในนั้น ระบบจะใช้พิกัดเลย์เอาต์ในขั้นตอนถัดไป
  2. สร้างตัวแปรสำหรับ PictureInPictureParams.Builder()
  3. เพิ่มคำสั่ง if เพื่อตรวจสอบว่า SDK เป็น S ขึ้นไปหรือไม่ หากใช่ ให้เพิ่ม setAutoEnterEnabled ลงในเครื่องมือสร้างและตั้งค่าเป็น true เพื่อเข้าสู่โหมด PiP เมื่อปัด ซึ่งจะทำให้ภาพเคลื่อนไหวราบรื่นกว่าการใช้ enterPictureInPictureMode
  4. ใช้ findActivity() เพื่อโทรหา setPictureInPictureParams() โทรหา build() ที่หมายเลข builder แล้วส่งต่อให้ผู้รับ

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)

ใช้ setAspectRatio เพื่อตั้งค่าสัดส่วนภาพของหน้าต่าง PiP

หากต้องการตั้งค่าสัดส่วนภาพของหน้าต่าง PIP คุณสามารถเลือกสัดส่วนภาพที่เฉพาะเจาะจงหรือใช้ความกว้างและความสูงของขนาดวิดีโอของเพลเยอร์ก็ได้ หากคุณใช้เพลเยอร์ media3 ให้ตรวจสอบว่าเพลเยอร์ไม่เป็นค่า Null และขนาดวิดีโอของเพลเยอร์ไม่เท่ากับ VideoSize.UNKNOWN ก่อนตั้งค่าสัดส่วนภาพ

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)

หากคุณใช้เพลเยอร์ที่กำหนดเอง ให้ตั้งค่าสัดส่วนการแสดงผลตามความสูงและความกว้างของเพลเยอร์โดยใช้ไวยากรณ์เฉพาะสำหรับเพลเยอร์ของคุณ โปรดทราบว่าหากเพลเยอร์ปรับขนาดระหว่างการเริ่มต้น และหากอยู่นอกขอบเขตที่ถูกต้องของสัดส่วนภาพ แอปจะขัดข้อง คุณอาจต้องเพิ่มการตรวจสอบว่าสามารถคำนวณสัดส่วนภาพได้เมื่อใด ซึ่งคล้ายกับวิธีที่ใช้กับเพลเยอร์ media3