ข่าวสารผลิตภัณฑ์

เครื่องมือเลือกรูปภาพแบบฝัง

ใช้เวลาอ่าน 8 นาที

เครื่องมือเลือกรูปภาพแบบฝัง: วิธีที่ราบรื่นยิ่งขึ้นในการขอรูปภาพและวิดีโอแบบส่วนตัวในแอป

photopicker.png

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

เหตุผลที่ควรฝัง

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

การผสานรวมที่ราบรื่นและความเป็นส่วนตัวที่ดียิ่งขึ้น

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

เครื่องมือเลือกรูปภาพที่ฝังใน Google Messages

Google Messages แสดงให้เห็นถึงศักยภาพของเครื่องมือเลือกรูปภาพแบบฝัง โดยมีวิธีผสานรวมดังนี้

  • ตำแหน่งที่ใช้งานง่าย: เครื่องมือเลือกรูปภาพจะอยู่ใต้ปุ่มกล้อง ซึ่งช่วยให้ผู้ใช้เลือกได้อย่างชัดเจนว่าจะถ่ายรูปภาพใหม่หรือเลือกรูปภาพที่มีอยู่
  • ตัวอย่างแบบไดนามิก: ทันทีที่ผู้ใช้แตะรูปภาพ ผู้ใช้จะเห็นตัวอย่างขนาดใหญ่ ซึ่งช่วยให้ยืนยันการเลือกได้ง่าย หากผู้ชมยกเลิกการเลือกรูปภาพ ตัวอย่างจะหายไปเพื่อให้ประสบการณ์การใช้งานสะอาดและไม่รก
  • ขยายเพื่อดูเนื้อหาเพิ่มเติม: มุมมองเริ่มต้นจะเรียบง่ายขึ้นเพื่อให้เข้าถึงรูปภาพล่าสุดได้ง่าย อย่างไรก็ตาม ผู้ใช้สามารถขยายเครื่องมือเลือกรูปภาพได้อย่างง่ายดายเพื่อเรียกดูและเลือกจากรูปภาพและวิดีโอทั้งหมดในคลัง รวมถึงเนื้อหาในระบบคลาวด์จาก Google Photos
  • เคารพตัวเลือกของผู้ใช้: เครื่องมือเลือกรูปภาพที่ฝังจะให้สิทธิ์เข้าถึงเฉพาะรูปภาพหรือวิดีโอที่ผู้ใช้เลือก ซึ่งหมายความว่าผู้ใช้สามารถหยุดขอสิทธิ์เข้าถึงรูปภาพและวิดีโอทั้งหมดได้ ซึ่งยังช่วยให้แอปข้อความไม่ต้องจัดการในกรณีที่ผู้ใช้ให้สิทธิ์เข้าถึงรูปภาพและวิดีโอแบบจำกัดเท่านั้น
gif1.gif
gif2.gif

การใช้งาน

ไลบรารี Jetpack ของเครื่องมือเลือกรูปภาพช่วยให้การผสานรวมเครื่องมือเลือกรูปภาพที่ฝังไว้เป็นเรื่องง่าย  

Jetpack Compose

ก่อนอื่น ให้รวมไลบรารีเครื่องมือเลือกรูปภาพ Jetpack เป็นการอ้างอิง

implementation("androidx.photopicker:photopicker-compose:1.0.0-alpha01")

ฟังก์ชันที่ประกอบกันได้ของ EmbeddedPhotoPicker มีกลไกในการรวม UI ของเครื่องมือเลือกรูปภาพที่ฝังไว้ภายในหน้าจอ Compose โดยตรง ฟังก์ชันที่ประกอบกันได้นี้สร้าง SurfaceView ซึ่งโฮสต์ UI ของเครื่องมือเลือกรูปภาพแบบฝัง โดยจะจัดการการเชื่อมต่อกับบริการ EmbeddedPhotoPicker จัดการการโต้ตอบของผู้ใช้ และสื่อสาร URI ของสื่อที่เลือกไปยังแอปพลิเคชันการโทร  

  @Composable
fun EmbeddedPhotoPickerDemo() {
    // We keep track of the list of selected attachments
    var attachments by remember { mutableStateOf(emptyList<Uri>()) }

    val coroutineScope = rememberCoroutineScope()
    // We hide the bottom sheet by default but we show it when the user clicks on the button
    val scaffoldState = rememberBottomSheetScaffoldState(
        bottomSheetState = rememberStandardBottomSheetState(
            initialValue = SheetValue.Hidden,
            skipHiddenState = false
        )
    )

    // Customize the embedded photo picker
    val photoPickerInfo = EmbeddedPhotoPickerFeatureInfo
        .Builder()
        // Set limit the selection to 5 items
        .setMaxSelectionLimit(5)
        // Order the items selection (each item will have an index visible in the photo picker)
        .setOrderedSelection(true)
        // Set the accent color (red in this case, otherwise it follows the device's accent color)
        .setAccentColor(0xFF0000)
        .build()

    // The embedded photo picker state will be stored in this variable
    val photoPickerState = rememberEmbeddedPhotoPickerState(
        onSelectionComplete = {
            coroutineScope.launch {
                // Hide the bottom sheet once the user has clicked on the done button inside the picker
                scaffoldState.bottomSheetState.hide()
            }
        },
        onUriPermissionGranted = {
            // We update our list of attachments with the new Uris granted
            attachments += it
        },
        onUriPermissionRevoked = {
            // We update our list of attachments with the Uris revoked
            attachments -= it
        }
    )

       SideEffect {
        val isExpanded = scaffoldState.bottomSheetState.targetValue == SheetValue.Expanded

        // We show/hide the embedded photo picker to match the bottom sheet state
        photoPickerState.setCurrentExpanded(isExpanded)
    }

    BottomSheetScaffold(
        topBar = {
            TopAppBar(title = { Text("Embedded Photo Picker demo") })
        },
        scaffoldState = scaffoldState,
        sheetPeekHeight = if (scaffoldState.bottomSheetState.isVisible) 400.dp else 0.dp,
        sheetContent = {
            Column(Modifier.fillMaxWidth()) {
                // We render the embedded photo picker inside the bottom sheet
                EmbeddedPhotoPicker(
                    state = photoPickerState,
                    embeddedPhotoPickerFeatureInfo = photoPickerInfo
                )
            }
        }
    ) { innerPadding ->
        Column(Modifier.padding(innerPadding).fillMaxSize().padding(horizontal = 16.dp)) {
            Button(onClick = {
                coroutineScope.launch {
                    // We expand the bottom sheet, which will trigger the embedded picker to be shown
                    scaffoldState.bottomSheetState.partialExpand()
                }
            }) {
                Text("Open photo picker")
            }
            LazyVerticalGrid(columns = GridCells.Adaptive(minSize = 64.dp)) {
                // We render the image using the Coil library
                itemsIndexed(attachments) { index, uri ->
                    AsyncImage(
                        model = uri,
                        contentDescription = "Image ${index + 1}",
                        contentScale = ContentScale.Crop,
                        modifier = Modifier.clickable {
                            coroutineScope.launch {
                                // When the user clicks on the media from the app's UI, we deselect it
                                // from the embedded photo picker by calling the method deselectUri
                                photoPickerState.deselectUri(uri)
                            }
                        }
                    )
                }
            }
        }
    }
}

ยอดดู

ก่อนอื่น ให้รวมไลบรารีเครื่องมือเลือกรูปภาพ Jetpack เป็นการอ้างอิง

implementation("androidx.photopicker:photopicker:1.0.0-alpha01")

หากต้องการเพิ่มเครื่องมือเลือกรูปภาพแบบฝัง คุณต้องเพิ่มรายการลงในไฟล์เลย์เอาต์  

  <view class="androidx.photopicker.EmbeddedPhotoPickerView"
    android:id="@+id/photopicker"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

และเริ่มต้นใช้งานในกิจกรรม/Fragment

  // We keep track of the list of selected attachments
private val _attachments = MutableStateFlow(emptyList<Uri>())
val attachments = _attachments.asStateFlow()

private lateinit var picker: EmbeddedPhotoPickerView
private var openSession: EmbeddedPhotoPickerSession? = null

val pickerListener = object EmbeddedPhotoPickerStateChangeListener {
    override fun onSessionOpened (newSession: EmbeddedPhotoPickerSession) {
        openSession = newSession
    }

    override fun onSessionError (throwable: Throwable) {}

    override fun onUriPermissionGranted(uris: List<Uri>) {
        _attachments += uris
    }

    override fun onUriPermissionRevoked (uris: List<Uri>) {
        _attachments -= uris
    }

    override fun onSelectionComplete() {
        // Hide the embedded photo picker as the user is done with the photo/video selection
    }
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main_view)
    
    //
    // Add the embedded photo picker to a bottom sheet to allow the dragging to display the full photo library
    //

    picker = findViewById(R.id.photopicker)
    picker.addEmbeddedPhotoPickerStateChangeListener(pickerListener)
    picker.setEmbeddedPhotoPickerFeatureInfo(
        // Set a custom accent color
        EmbeddedPhotoPickerFeatureInfo.Builder().setAccentColor(0xFF0000).build()
    )
}

คุณสามารถเรียกวิธีการต่างๆ ของ EmbeddedPhotoPickerSession เพื่อโต้ตอบกับเครื่องมือเลือกแบบฝัง

  // Notify the embedded picker of a configuration change
openSession.notifyConfigurationChanged(newConfig)

// Update the embedded picker to expand following a user interaction
openSession.notifyPhotoPickerExpanded(/* expanded: */ true)

// Resize the embedded picker
openSession.notifyResized(/* width: */ 512, /* height: */ 256)

// Show/hide the embedded picker (after a form has been submitted)
openSession.notifyVisibilityChanged(/* visible: */ false)

// Remove unselected media from the embedded picker after they have been
// unselected from the host app's UI
openSession.requestRevokeUriPermission(removedUris)

โปรดทราบว่าประสบการณ์เครื่องมือเลือกรูปภาพแบบฝังพร้อมให้บริการแก่ผู้ใช้ที่ใช้ Android 14 (ระดับ API 34) ขึ้นไปที่มี SDK Extensions 15 ขึ้นไป อ่านเพิ่มเติมเกี่ยวกับความพร้อมใช้งานของเครื่องมือเลือกรูปภาพในอุปกรณ์

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

หากมีข้อเสนอแนะหรือความคิดเห็น โปรดส่งคำขอแจ้งปัญหาไปยังIssue Tracker

เขียนโดย

อ่านต่อ