ใช้ไลบรารีการแสดงภาพซ้อนภาพของ Jetpack

ไลบรารี Jetpack สำหรับการแสดงภาพซ้อนภาพ (PIP) มีโซลูชันที่มีประสิทธิภาพและ แข็งแกร่งสำหรับนักพัฒนาแอป Android ในการใช้ฟังก์ชัน PIP โดยเฉพาะอย่างยิ่งสำหรับการเล่นสื่อ การสื่อสารผ่านวิดีโอ และแอปนำทาง ไลบรารีนี้มี API แบบรวม ซึ่งช่วยลดโค้ดมาตรฐาน ข้อบกพร่องทั่วไปในแอป และปรับปรุงคุณภาพโดยรวมของประสบการณ์การใช้งาน PiP

ไลบรารี PiP Jetpack ช่วยอำนวยความสะดวกให้แก่ PiP API ที่มีอยู่โดยการแก้ไขความท้าทายและความไม่สอดคล้องกันที่สำคัญหลายประการในระบบนิเวศของ Android ดังนี้

  • การกระจายตัวของระบบปฏิบัติการ: ไลบรารีจะจัดการความแตกต่างในการเรียกใช้ PIP API ใน Android เวอร์ชันต่างๆ โดยอัตโนมัติ เช่น การใช้ enterPictureInPictureMode ก่อน Android 12 และ isAutoEnterEnabled หลังจากนั้น เพื่อให้นักพัฒนาแอปไม่ต้องจัดการความแตกต่างของเวอร์ชัน
  • พารามิเตอร์ PiP ไม่ถูกต้อง: มีโซลูชันแบบรวมสำหรับการตั้งค่าพารามิเตอร์ PiP อย่างถูกต้อง เช่น setSourceRectHint เพื่อสร้างภาพเคลื่อนไหวที่ราบรื่นและมีคุณภาพสูงในระหว่างการเล่นสื่อ
  • การเรียกกลับสถานะ PIP แบบรวม: รวม onPictureInPictureModeChanged และ onPictureInPictureUiStateChanged ไว้ในการเรียกกลับแบบรวมเดียว อินเทอร์เฟซ (PictureInPictureDelegate.OnPictureInPictureEventListener) เพื่อ การจัดการสถานะและ UI ที่ง่ายขึ้น
  • การลดโค้ดสำเร็จรูป: ไลบรารีจะลดปริมาณโค้ดสำเร็จรูปที่ซ้ำกัน โดยการเสนอชุด RemoteActions ที่กำหนดไว้ล่วงหน้าสำหรับการใช้งานทั่วไป เช่น ตัวควบคุมการเล่นและการดำเนินการในการวิดีโอคอล
  • การเตรียมพร้อมสำหรับอนาคต: ฟีเจอร์ PiP เพิ่มเติมจะให้บริการผ่านไลบรารี Jetpack ซึ่งช่วยให้ผู้ใช้เข้าถึงฟังก์ชันการทำงานเพิ่มเติมได้โดยใช้ความพยายามเพียงเล็กน้อยหรือแทบไม่ต้องทำอะไรเลย

เวิร์กโฟลว์การย้ายข้อมูล

ระบุหมวดหมู่กรณีการใช้งานของแอปและตรรกะ PiP เดิม

หมวดหมู่: การเล่นวิดีโอ การนำทาง หรือวิดีโอคอล

ตรรกะ PiP เดิมที่ใช้ระบุ:

  • onUserLeaveHint
  • setAutoEnterEnabled
  • onPictureInPictureModeChanged
  • onPictureInPictureUiStateChanged
  • setPictureInPictureParams

2. การกำหนดค่า AndroidManifest

ตรวจสอบว่ากิจกรรมที่เข้าสู่ PIP ประกาศการรองรับใน AndroidManifest.xml พร้อมด้วย configChanges ที่จำเป็นเพื่อป้องกันการรีสตาร์ทที่ไม่จำเป็น

<activity
android:name="VideoActivity" android:supportsPictureInPicture="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation">
</activity>

3. การตั้งค่าสภาพแวดล้อม

เพิ่มทรัพยากร Dependency ที่จำเป็นลงใน build.gradle ดังนี้

dependencies {
implementation("androidx.core:core:1.18.0")
implementation("androidx.activity:activity:1.13.0")
implementation("androidx.core:core-pip:1.0.0-alpha02") }

ใช้ไลบรารี AndroidX ล่าสุดสำหรับทรัพยากร Dependency และดูข้อมูลดังกล่าวได้ในหน้ารุ่น

4. การเลือกและการเริ่มต้นเทมเพลต

เลือกเทมเพลตการติดตั้งใช้งานที่เหมาะกับกรณีการใช้งานของแอปมากที่สุด

  • การนำทางและวิดีโอคอล: BasicPictureInPicture โดยปกติแล้วระบบจะไม่รองรับการปรับขนาดที่ราบรื่น และคุณไม่จำเป็นต้องมีคำแนะนำเกี่ยวกับสี่เหลี่ยมผืนผ้าต้นทาง
  • การเล่นวิดีโอ: VideoPlaybackPictureInPicture; ติดตามขอบเขตมุมมองของเพลเยอร์โดยอัตโนมัติสำหรับคำแนะนำเกี่ยวกับสี่เหลี่ยมผืนผ้าต้นทาง และเปิดใช้การปรับขนาดที่ราบรื่นโดย ค่าเริ่มต้น

หากต้องการใช้ Jetpack Library ให้แทนที่การใช้งาน PIP ที่กำหนดเองที่มีอยู่ด้วย API ของ Jetpack Library ความซับซ้อนและต้นทุนในการ นำไปใช้จะแตกต่างกันไปตามการติดตั้งใช้งานปัจจุบันของแอป

ส่วนต่อไปนี้จะอธิบายกรณีการใช้งานทั่วไปบางส่วนของ PIP และ ขั้นตอนการติดตั้งใช้งานที่จำเป็น

แอปจะแจ้งสถานะการนำทางที่ใช้งานอยู่หรือไม่ใช้งานให้ไลบรารีทราบและ ตั้งค่าสัดส่วนภาพ ส่วนที่เหลือไลบรารี Jetpack จะจัดการให้เอง

ความแตกต่างที่สำคัญ

  1. ไม่จำเป็นต้องแยกความแตกต่างระหว่างการป้อนอัตโนมัติกับการป้อนแบบเดิมในฝั่งแอป
  2. อินเทอร์เฟซการเรียกกลับที่รวมไว้
  3. PictureInPictureParams ตัวสร้างใหม่เพื่อความเข้ากันได้แบบย้อนหลัง

วิดีโอคอล

แอปจะแจ้งสถานะการโทรว่าใช้งานอยู่หรือไม่ให้ไลบรารีทราบ และตั้งค่า สัดส่วนภาพ

ความแตกต่างที่สำคัญ

  1. ไม่จำเป็นต้องแยกความแตกต่างระหว่างการป้อนอัตโนมัติกับการป้อนแบบเดิมในฝั่งแอป
  2. อินเทอร์เฟซการเรียกกลับที่รวมไว้
  3. PictureInPictureParams ตัวสร้างใหม่เพื่อความเข้ากันได้แบบย้อนหลัง
  4. ไอคอนการดำเนินการที่เป็นมาตรฐานสำหรับวิดีโอคอล

5. การย้ายข้อมูลโค้ด

  • ตรรกะรายการ: แทนที่ตรรกะเฉพาะ API เช่น setAutoEnterEnabled สำหรับ Android 12 ขึ้นไป หรือ onUserLeaveHint สำหรับ Android 11 ลงไป ด้วย setEnabled ทริกเกอร์การดำเนินการนี้เมื่อใดก็ตามที่สถานะการมีสิทธิ์ใช้ PIP มีการเปลี่ยนแปลง
  • การเรียกกลับ: รวม onPictureInPictureModeChanged (การสลับเลย์เอาต์) และ onPictureInPictureUiStateChanged (ภาพเคลื่อนไหว/สถานะ) ไว้ในการเรียกกลับตามเหตุการณ์แบบรวม onPictureInPictureEvent
  • การดำเนินการและพารามิเตอร์: อัปเดตพารามิเตอร์โดยใช้ setActions และ setAspectRatio ในอินสแตนซ์เทมเพลตทุกครั้งที่มีการเปลี่ยนแปลง
  • การจัดการวิดีโอเป็นพิเศษ: สำหรับแอปวิดีโอ ให้ใช้ setPlayerView เพื่ออัปเดตคำแนะนำเกี่ยวกับสี่เหลี่ยมผืนผ้าต้นทางโดยอัตโนมัติและรับประกันการเปลี่ยนฉากที่ราบรื่น ` ### 6. ล้างข้อมูล

สำหรับ VideoPlaybackPictureInPicture ให้เรียกใช้ close ใน onDispose หรือ onDestroy เพื่อปล่อยทรัพยากร เช่น ตัวติดตามการดู

รูปแบบการใช้งานอ้างอิง

ตัวอย่างการใช้งาน

การนำทางและวิดีโอคอล

class NavOrVideoCallJpipActivity : ComponentActivity(), PictureInPictureDelegate.OnPictureInPictureEventListener {
    private lateinit var pictureInPictureImpl: BasicPictureInPicture
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        pictureInPictureImpl = BasicPictureInPicture(this)
        // BasicPictureInPicture is ideal for Navigation and Video call use cases.
        pictureInPictureImpl.addOnPictureInPictureEventListener(
            ContextCompat.getMainExecutor(this),
            this
        )
        setContent {
        }
    }
    override fun onPictureInPictureEvent(
        event: PictureInPictureDelegate.Event,
        config: Configuration?
    ) {
        when (event) {
            PictureInPictureDelegate.Event.ENTERED -> { /* Toggle to PiP layout */ }
            PictureInPictureDelegate.Event.EXITED -> { /* Toggle to Full-screen layout */ }
            PictureInPictureDelegate.Event.STASHED -> { /* Optional: PiP is stashed */ }
            PictureInPictureDelegate.Event.UNSTASHED -> { /* Optional: PiP is unstashed */ }
        }
    }
}

การเล่นวิดีโอ

class VideoPlaybackJpipActivity : ComponentActivity(), PictureInPictureDelegate.OnPictureInPictureEventListener {
    private lateinit var pictureInPictureImpl: VideoPlaybackPictureInPicture
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        pictureInPictureImpl = VideoPlaybackPictureInPicture(this)
        pictureInPictureImpl.addOnPictureInPictureEventListener(
            ContextCompat.getMainExecutor(this),
            this
        )
        setContent {
            ContentScreen(pictureInPictureImpl)
        }
    }
    override fun onPictureInPictureEvent(
        event: PictureInPictureDelegate.Event,
        config: Configuration?
    ) {
        when (event) {
            PictureInPictureDelegate.Event.ENTER_ANIMATION_START -> { /* Hide overlays */ }
            PictureInPictureDelegate.Event.ENTER_ANIMATION_END -> { /* Animation finished */ }
            PictureInPictureDelegate.Event.ENTERED -> { /* Switch to PiP layout */ }
            PictureInPictureDelegate.Event.STASHED -> { /* PiP stashed */ }
            PictureInPictureDelegate.Event.UNSTASHED -> { /* PiP unstashed */ }
            PictureInPictureDelegate.Event.EXITED -> { /* Return to full-screen */ }
        }
    }

    @Composable
    fun ContentScreen(pipController: VideoPlaybackPictureInPicture) {
        DisposableEffect(pipController) {
            onDispose {
                pipController.close()
            }
        }
    }
}