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