O framework do Android baseado na área de transferência para copiar e colar. oferece suporte a tipos de dados primitivos e complexos, incluindo:
- Strings de texto
- Estruturas de dados complexas
- Dados de fluxo de texto e binário
- Recursos do aplicativo
Dados de texto simples são armazenados diretamente na área de transferência, enquanto dados complexos são armazenados como referência que o aplicativo de colagem resolve com um provedor de conteúdo.
O recurso de copiar e colar funciona dentro e entre aplicativos que implementam a estrutura.
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 oferecem suporte à cópia e colagem de texto fora da caixa, conforme mostrado na tabela a seguir.
Componente | Copiar texto | Colando texto |
---|---|---|
Campo de texto básico | ✅ | ✅ |
Campo de texto | ✅ | ✅ |
Contêiner de seleção | ✅ |
Por exemplo, você pode copiar o texto do card para a área de transferência
no snippet a seguir e colar o texto copiado no TextField
.
Para mostrar 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
É possível copiar textos para a área de transferência com o ClipboardManager
.
O método setText() copia
o objeto String 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("Hello, clipboard")
}
) {
Text("Click to copy a text")
}
O snippet a seguir faz o mesmo, mas oferece um controle mais granular.
Um caso de uso comum é a cópia de conteúdo sensível,
como a 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.
ClipData.newPlainText()
é um método conveniente para
criar um objeto ClipData
com base em um objeto String.
É possível definir o objeto ClipEntry
criado na área de transferência
chamando o método setClip()
sobre o 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
É possível acessar o texto copiado para a área de transferência
chamando o método getText()
no ClipboardManager
.
O método getText()
retorna um objeto AnnotatedString
quando um texto é copiado na área de transferência.
O snippet a seguir anexa texto na área de transferência
ao texto na TextField
.
var 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(text.toString())
}
}
}
) {
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.
O app pode permitir que o usuário copie conteúdo rico 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 rico 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 colar conteúdo rico
em BasicTextField
no componente modificado.
O snippet de código a seguir adiciona o URI colado de dados de imagem.
a uma lista de objetos Uri
.
// A URI list of images
val imageList by remember{ mutableListOf<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 onReceber,
que descreve os dados que podem ser transferidos entre apps
colando neste caso.
Você pode acessar o objeto ClipEntry
referindo-se ao 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 cada objeto ClipData.Item
como consumido ou ignorado.
e retornar uma TransferableContent
contendo
os objetos ClipData.Item
ignorados
para que o modificador contentReceiver
do 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 retorna 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 forma que você faz para o conteúdo rico. 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 rico.
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 usado para copiar e colar, O Android mostra uma interface padrão para os usuários quando eles fazem cópias no Android 13 (nível 33 da API) e superiores. Devido a esse recurso, há o risco de notificação duplicada. Saiba mais sobre esse caso extremo em Evitar notificações duplicadas.
Enviar feedback manualmente aos usuários ao copiar no Android 12L (nível 32 da API) e versões anteriores. Consulte a recomendação.
Conteúdo sensível
Se você permitir que o usuário copie conteúdo sensível para a área de transferência, como senhas, o app precisa informar ao sistema para que o sistema evite a exibição do conteúdo sensível copiado na interface (Figura 2).
É necessário adicionar uma flag a ClipDescription
em ClipData
antes de chamar o método setClip()
sobre o 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)
}
}