O framework baseado na área de transferência do Android para copiar e colar oferece suporte a tipos de dados primitivos e complexos, incluindo:
- Strings de texto
- Estruturas de dados complexas
- Dados de stream de texto e binários
- Recursos do aplicativo
Os dados de texto simples são armazenados diretamente na área de transferência, enquanto os dados complexos são armazenados como uma referência que o aplicativo de colagem resolve com um provedor de conteúdo.
A cópia e a colagem funcionam tanto em um aplicativo quanto entre aplicativos que implementam o framework.
Como parte do framework usa provedores de conteúdo, este documento pressupõe certa familiaridade com a API Android Content Provider.
Trabalhar com texto
Alguns componentes são compatíveis com copiar e colar texto, conforme mostrado na tabela a seguir.
| Componente | Copiando texto | Colar texto |
|---|---|---|
| BasicTextField | ✅ | ✅ |
| TextField | ✅ | ✅ |
| SelectionContainer | ✅ |
Por exemplo, é possível copiar o texto do card para a área de transferência
no snippet a seguir e colar o texto copiado no TextField.
Para exibir o menu e colar o texto, toque e pressione o TextField ou toque na alça do cursor.
val textFieldState = rememberTextFieldState() Column { Card { SelectionContainer { Text("You can copy this text") } } BasicTextField(state = textFieldState) }
Você pode colar o texto com o seguinte atalho de teclado: Ctrl+V . O atalho do teclado também está disponível por padrão. Consulte Processar ações do teclado para mais detalhes.
Copiar com ClipboardManager
Você pode copiar textos para a área de transferência com ClipboardManager.
O método setText() copia
o objeto AnnotatedString transmitido para a área de transferência.
O snippet a seguir copia "Hello, clipboard"
para a área de transferência quando o usuário clica no botão.
// Retrieve a ClipboardManager object val clipboardManager = LocalClipboardManager.current Button( onClick = { // Copy "Hello, clipboard" to the clipboard clipboardManager.setText(AnnotatedString("Hello, clipboard")) } ) { Text("Click to copy a text") }
O snippet a seguir faz a mesma coisa, mas oferece um controle mais granular.
Um caso de uso comum é copiar conteúdo sensível,
como uma senha. ClipEntry descreve um item na área de transferência.
Ele contém um objeto ClipData que descreve os dados na área de transferência.
O método ClipData.newPlainText() é um método de conveniência para
criar um objeto ClipData de um objeto String.
É possível definir o objeto ClipEntry criado para a área de transferência
chamando o método setClip()
no objeto ClipboardManager.
// Retrieve a ClipboardManager object val clipboardManager = LocalClipboardManager.current Button( onClick = { val clipData = ClipData.newPlainText("plain text", "Hello, clipboard") val clipEntry = ClipEntry(clipData) clipboardManager.setClip(clipEntry) } ) { Text("Click to copy a text") }
Colar com o ClipboardManager
Para acessar o texto copiado para a área de transferência,
chame o método getText()
em ClipboardManager.
O método getText() retorna um objeto AnnotatedString
quando um texto é copiado na área de transferência.
O snippet a seguir anexa o texto na área de transferência
ao texto no TextField.
val textFieldState = rememberTextFieldState() Column { TextField(state = textFieldState) Button( onClick = { // The getText method returns an AnnotatedString object or null val annotatedString = clipboardManager.getText() if (annotatedString != null) { // The pasted text is placed on the tail of the TextField textFieldState.edit { append(annotatedString.text) } } } ) { Text("Click to paste the text in the clipboard") } }
Trabalhar com conteúdo avançado
Os usuários adoram imagens, vídeos e outros conteúdos expressivos.
Seu app pode permitir que o usuário copie conteúdo avançado com
ClipboardManager e ClipEntry.
O modificador contentReceiver ajuda a implementar a colagem de conteúdo avançado.
Copiar conteúdo avançado
O app não pode copiar conteúdo avançado diretamente para a área de transferência.
Em vez disso, o app transmite um objeto URI para a área de transferência
e fornece acesso ao conteúdo com um ContentProvider.
O snippet de código a seguir mostra como copiar uma imagem JPEG para a área de transferência.
Consulte Copiar fluxos de dados para mais detalhes.
// Get a reference to the context val context = LocalContext.current Button( onClick = { // URI of the copied JPEG data val uri = Uri.parse("content://your.app.authority/0.jpg") // Create a ClipData object from the URI value // A ContentResolver finds a proper ContentProvider so that ClipData.newUri can set appropriate MIME type to the given URI val clipData = ClipData.newUri(context.contentResolver, "Copied", uri) // Create a ClipEntry object from the clipData value val clipEntry = ClipEntry(clipData) // Copy the JPEG data to the clipboard clipboardManager.setClip(clipEntry) } ) { Text("Copy a JPEG data") }
Colar um conteúdo avançado
Com o modificador contentReceiver, é possível processar a colagem de conteúdo avançado
em BasicTextField no componente modificado.
O snippet de código a seguir adiciona o URI colado de dados de uma imagem
a uma lista de objetos Uri.
// A URI list of images val imageList = remember { mutableStateListOf<Uri>() } // Remember the ReceiveContentListener object as it is created inside a Composable scope val receiveContentListener = remember { ReceiveContentListener { transferableContent -> // Handle the pasted data if it is image data when { // Check if the pasted data is an image or not transferableContent.hasMediaType(MediaType.Image) -> { // Handle for each ClipData.Item object // The consume() method returns a new TransferableContent object containging ignored ClipData.Item objects transferableContent.consume { item -> val uri = item.uri if (uri != null) { imageList.add(uri) } // Mark the ClipData.Item object consumed when the retrieved URI is not null uri != null } } // Return the given transferableContent when the pasted data is not an image else -> transferableContent } } } val textFieldState = rememberTextFieldState() BasicTextField( state = textFieldState, modifier = Modifier .contentReceiver(receiveContentListener) .fillMaxWidth() .height(48.dp) )
O modificador contentReceiver usa um objeto ReceiveContentListener
como argumento e chama o método onReceive
do objeto transmitido quando o usuário cola dados
no BasicTextField dentro do componente modificado.
Um objeto TransferableContent é transmitido para o método onReceive,
que descreve os dados que podem ser transferidos entre apps
ao colar, neste caso.
Você pode acessar o objeto ClipEntry consultando o atributo clipEntry.
Um objeto ClipEntry pode ter vários objetos ClipData.Item
quando o usuário seleciona várias imagens e as copia para a área de transferência,
por exemplo.
Marque como consumido ou ignorado para cada objeto ClipData.Item
e retorne um TransferableContent contendo
os objetos ClipData.Item ignorados
para que o modificador contentReceiver ancestral mais próximo possa recebê-lo.
O método TransferableContent.hasMediaType() pode ajudar a determinar
se o objeto TransferableContent pode fornecer um item
com o tipo de mídia.
Por exemplo, a chamada de método a seguir retornará true
se o objeto TransferableContent puder fornecer uma imagem.
transferableContent.hasMediaType(MediaType.Image)
Trabalhar com dados complexos
É possível copiar dados complexos para a área de transferência da mesma maneira que você faz com o conteúdo avançado. Consulte Usar provedores de conteúdo para copiar dados complexos para mais detalhes.
Também é possível processar as colagens de dados complexos
da mesma maneira para o conteúdo avançado.
Você pode receber um URI dos dados colados.
Os dados reais podem ser recuperados de um ContentProvider.
Consulte Recuperar dados do provedor para mais informações.
Feedback sobre a cópia de conteúdo
Os usuários esperam feedback ao copiar conteúdo para a área de transferência. Portanto, além do framework que permite copiar e colar, o sistema mostra uma IU padrão quando usuários executam ações de cópia no Android 13 (nível 33 da API) e versões mais recentes. Devido a esse recurso, há o risco de notificações duplicadas. Saiba mais sobre esse caso extremo em Evitar notificações duplicadas.
Envie feedback manualmente aos usuários que executam ações de cópia no Android 12L (nível da API 32) e versões anteriores. Consulte a recomendação.
Conteúdo sensível
Se você permitir que o app copie conteúdo sensível para a área de transferência, como senhas, o app precisará informar o sistema para que ele evite mostrar o conteúdo sensível copiado na interface (figura 2).
Adicione uma flag a ClipDescription em ClipData
antes de chamar o método setClip() no objeto ClipboardManager:
// If your app is compiled with the API level 33 SDK or higher. clipData.apply { description.extras = PersistableBundle().apply { putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true) } } // If your app is compiled with a lower SDK. clipData.apply { description.extras = PersistableBundle().apply { putBoolean("android.content.extra.IS_SENSITIVE", true) } }