Notícias sobre produtos

Seletor de fotos incorporado

Leitura de 8 minutos

Seletor de fotos incorporado: uma maneira mais simples de solicitar fotos e vídeos particulares no seu app

photopicker.png

Planeje e prepare-se para melhorar a experiência do usuário do seu app com uma nova maneira de usar o seletor de fotos do Android. O novo seletor de fotos incorporado oferece uma maneira simples e focada na privacidade para os usuários selecionarem fotos e vídeos diretamente na interface do seu app. Agora, seu app pode aproveitar todos os benefícios disponíveis com o seletor de fotos, incluindo o acesso ao conteúdo da nuvem, integrado diretamente à experiência do app.

Por que incorporado?

Entendemos que muitos apps querem oferecer uma experiência altamente integrada e simples para os usuários ao selecionar fotos ou vídeos. O seletor de fotos incorporado foi projetado para fazer exatamente isso, permitindo que os usuários acessem rapidamente as fotos recentes sem sair do seu app. Eles também podem explorar toda a biblioteca no provedor de mídia na nuvem preferido (por exemplo, o Google Fotos), incluindo favoritos, álbuns e funcionalidade de pesquisa. Isso elimina a necessidade de os usuários alternarem entre apps ou se preocuparem se a foto desejada está armazenada localmente ou na nuvem.

Integração total, privacidade aprimorada

Com o seletor de fotos incorporado, seu app não precisa de acesso às fotos ou vídeos do usuário até que ele selecione algo. Isso significa maior privacidade para os usuários e uma experiência mais simples. Além disso, o seletor de fotos incorporado oferece aos usuários acesso a toda a biblioteca de mídia baseada na nuvem, enquanto a permissão de foto padrão é restrita apenas a arquivos locais.

O seletor de fotos incorporado no Google Mensagens

O Google Mensagens mostra o poder do seletor de fotos incorporado. Confira como ele foi integrado:

  • Posicionamento intuitivo : o seletor de fotos fica logo abaixo do botão da câmera, oferecendo aos usuários uma escolha clara entre capturar uma nova foto ou selecionar uma existente.
  • Visualização dinâmica:imediatamente depois que um usuário toca em uma foto, ele vê uma visualização grande, facilitando a confirmação da seleção. Se a foto for desmarcada, a visualização desaparece, mantendo a experiência limpa e organizada.
  • Expandir para mais conteúdo : a visualização inicial é simplificada, oferecendo acesso fácil às fotos recentes. No entanto, os usuários podem expandir facilmente o seletor de fotos para navegar e escolher entre todas as fotos e vídeos na biblioteca, incluindo conteúdo da nuvem do Google Fotos.
  • Respeitar as escolhas do usuário:o seletor de fotos incorporado só concede acesso às fotos ou vídeos específicos selecionados pelo usuário, o que significa que ele pode parar de solicitar as permissões de foto e vídeo. Isso também evita que o Mensagens precise lidar com situações em que os usuários concedem apenas acesso limitado a fotos e vídeos.
gif1.gif
gif2.gif

Implementação

A integração do seletor de fotos incorporado é facilitada pela biblioteca do Jetpack do seletor de fotos.  

Jetpack Compose

Primeiro, inclua a biblioteca do Jetpack do seletor de fotos como uma dependência.

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

A função combinável EmbeddedPhotoPicker fornece um mecanismo para incluir a interface do seletor de fotos incorporado diretamente na tela do Compose. Esse elemento combinável cria uma SurfaceView que hospeda a interface do seletor de fotos incorporado. Ele gerencia a conexão com o serviço EmbeddedPhotoPicker, processa as interações do usuário e comunica os URIs de mídia selecionados ao aplicativo de chamada.  

  @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)
                            }
                        }
                    )
                }
            }
        }
    }
}

Visualizações

Primeiro, inclua a biblioteca do Jetpack do seletor de fotos como uma dependência.

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

Para adicionar o seletor de fotos incorporado, adicione uma entrada ao arquivo de layout.  

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

E inicialize-o na atividade/fragmento.

  // 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()
    )
}

É possível chamar diferentes métodos de EmbeddedPhotoPickerSession para interagir com o seletor incorporado.

  // 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)

É importante observar que a experiência do seletor de fotos incorporado está disponível para usuários que executam o Android 14 (nível 34 da API) ou mais recente com as Extensões do SDK 15 ou mais recentes. Saiba mais sobre a disponibilidade do dispositivo do seletor de fotos.

Para melhorar a privacidade e a segurança do usuário, o sistema renderiza o seletor de fotos incorporado de uma maneira que impede qualquer desenho ou sobreposição. Essa escolha de design intencional significa que sua UX precisa considerar a área de exibição do seletor de fotos como um elemento distinto e dedicado, assim como você planeja um banner publicitário.

Se você tiver feedback ou sugestões, envie tickets para nosso rastreador de problemas.

Escrito por:

Continuar lendo