O seletor de fotos incorporado: uma maneira mais fácil de solicitar fotos e vídeos de forma privada no seu app
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 integrado oferece uma maneira simples e focada na privacidade para os usuários selecionarem fotos e vídeos diretamente na interface do app. Agora seu app pode aproveitar todos os mesmos benefícios disponíveis com o seletor de fotos, incluindo acesso a conteúdo na nuvem, integrado diretamente à experiência do app.
Por que usar o recurso 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 isso. Ele permite que os usuários acessem rapidamente as fotos recentes sem sair do seu app. Eles também podem explorar a biblioteca completa no provedor de mídia na nuvem preferido (por exemplo, Google Fotos), incluindo favoritos, álbuns e funcionalidade de pesquisa. Assim, os usuários não precisam alternar entre apps nem se preocupar se a foto que querem está armazenada localmente ou na nuvem.
Integração total e privacidade aprimorada
Com o seletor de fotos incorporado, o app não precisa de acesso às fotos ou vídeos do usuário até que ele selecione algo. Isso significa mais privacidade para os usuários e uma experiência mais simplificada. 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 padrão de fotos é restrita apenas a arquivos locais.
O seletor de fotos incorporado no Google Mensagens
O Google Mensagens mostra o poder do seletor de fotos incorporado. Veja como eles fizeram isso:
- 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 já existente.
- Visualização dinâmica:assim que um usuário toca em uma foto, uma visualização grande aparece, facilitando a confirmação da seleção. Se eles desmarcarem a foto, a prévia vai desaparecer, 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.
- Respeito às escolhas do usuário:o seletor de fotos incorporado só concede acesso às fotos ou vídeos específicos que o usuário seleciona. Isso significa que ele pode parar de solicitar as permissões de foto e vídeo. Isso também evita que o app Mensagens precise lidar com situações em que os usuários concedem apenas acesso limitado a fotos e vídeos.
Implementação
A integração do seletor de fotos incorporado é facilitada com a biblioteca do Jetpack Photo Picker.
Jetpack Compose
Primeiro, inclua a biblioteca Jetpack Photo Picker como uma dependência.
implementation("androidx.photopicker:photopicker-compose:1.0.0-alpha01")
A função combinável EmbeddedPhotoPicker oferece 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, lida com 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 Jetpack Photo Picker 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 sua 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 usam o Android 14 (nível da API 34) ou versões mais recentes com as extensões do SDK 15 ou mais recentes. Leia mais sobre a disponibilidade do seletor de fotos em dispositivos.
Para aumentar a privacidade e a segurança do usuário, o sistema renderiza o seletor de fotos incorporado de forma a evitar 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 tiver feedback ou sugestões, envie tíquetes para nosso rastreador de problemas.
-
Novidades sobre produtosA privacidade e o controle do usuário continuam sendo o foco da experiência do Android. Assim como o seletor de fotos tornou o compartilhamento de mídia seguro e fácil de implementar, agora estamos trazendo o mesmo nível de privacidade, simplicidade e ótima experiência do usuário para a seleção de contatos.
Roxanna Aliabadi Walker • Leitura de 4 minutos -
Novidades sobre produtosHoje, temos o prazer de anunciar o lançamento estável das bibliotecas AndroidX Security State versão 1.1.0 e Security State Provider versão 1.0.0.
Maunik Shah, Alec Garcia, Joseph Yong • Leitura de 4 minutos -
Novidades sobre produtosHoje, estamos lançando o primeiro conjunto de tarefas de longo prazo (LHT, na sigla em inglês), que são tarefas de grande complexidade que levam vários dias ou até uma semana para serem concluídas por um engenheiro. Também estamos lançando a avaliação com agentes, começando com agentes dos provedores de modelos correspondentes.
Matthew McCullough • Leitura de 3 minutos
Receba os insights mais recentes sobre desenvolvimento Android na sua caixa de entrada semanalmente.