Il framework basato sugli appunti di Android per copiare e incollare supporta tipi di dati primitivi e complessi, tra cui:
- Stringhe di testo
- Strutture di dati complesse
- Dati di stream di testo e binari
- Asset dell'applicazione
I dati di testo semplici vengono archiviati direttamente negli appunti, mentre i dati complessi vengono archiviati come riferimento che l'applicazione di incollatura risolve con un provider di contenuti.
La copia e l'incollatura funzionano sia all'interno di un'applicazione sia tra applicazioni che implementano il framework.
Poiché una parte del framework utilizza i provider di contenuti, questo documento presuppone una certa familiarità con l'API Provider di contenuti di Android.
Utilizzare il testo
Alcuni componenti supportano la copia e l'incollatura del testo out-of-the-box, come mostrato nella tabella seguente.
| Componente | Copia del testo | Incollatura del testo |
|---|---|---|
| BasicTextField | ✅ | ✅ |
| TextField | ✅ | ✅ |
| SelectionContainer | ✅ |
Ad esempio, puoi copiare il testo nella scheda negli appunti nel seguente snippet e incollare il testo copiato in TextField.
Per visualizzare il menu per incollare il testo, tocca e tieni premuto TextField o tocca la maniglia del cursore.
val textFieldState = rememberTextFieldState() Column { Card { SelectionContainer { Text("You can copy this text") } } BasicTextField(state = textFieldState) }
Puoi incollare il testo con la seguente scorciatoia da tastiera: Ctrl+V . La scorciatoia da tastiera è disponibile anche per impostazione predefinita. Per maggiori dettagli, consulta Gestire le azioni della tastiera.
Copiare con ClipboardManager
Puoi copiare i testi negli appunti con ClipboardManager.
Il suo metodo setText() copia
l'oggetto AnnotatedString passato negli appunti.
Il seguente snippet copia "Hello, clipboard" negli appunti quando l'utente fa clic sul pulsante.
// 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") }
Il seguente snippet fa la stessa cosa, ma ti offre un controllo più granulare.
Un caso d'uso comune è la copia di contenuti sensibili,
come le password. ClipEntry descrive un elemento negli appunti.
Contiene un ClipData oggetto che descrive i dati negli appunti.
ClipData.newPlainText() method is a convenience method to
create a ClipData object from a String object.
Puoi impostare l'oggetto ClipEntry creato negli appunti
chiamando il metodo setClip()
sull'oggetto 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") }
Incollare con ClipboardManager
Puoi accedere al testo copiato negli appunti
chiamando il getText() metodo
su ClipboardManager.
Il metodo getText() restituisce un oggetto AnnotatedString quando un testo viene copiato negli appunti.
Il seguente snippet aggiunge il testo negli appunti al testo in 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") } }
Utilizzare contenuti avanzati
Gli utenti amano immagini, video e altri contenuti espressivi.
La tua app può consentire all'utente di copiare contenuti avanzati con ClipboardManager e ClipEntry.
Il modificatore contentReceiver ti aiuta a implementare l'incollatura di contenuti avanzati.
Copiare contenuti avanzati
La tua app non può copiare direttamente contenuti avanzati negli appunti.
La tua app passa invece un oggetto URI agli appunti
e fornisce l'accesso ai contenuti con un ContentProvider.
Il seguente snippet di codice mostra come copiare un'immagine JPEG negli appunti.
Per maggiori dettagli, consulta Copiare gli stream di dati.
// 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") }
Incollare contenuti avanzati
Con il modificatore contentReceiver, puoi gestire l'incollatura di contenuti avanzati
in BasicTextField nel componente modificato.
Il seguente snippet di codice aggiunge l'URI incollato dei dati di un'immagine
a un elenco di Uri oggetti.
// 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) )
Il modificatore contentReceiver accetta un ReceiveContentListener oggetto
come argomento e chiama il metodo onReceive
dell'oggetto passato quando l'utente incolla i dati
in BasicTextField all'interno del componente modificato.
Al metodo onReceive viene passato un oggetto TransferableContent,
che descrive i dati che possono essere trasferiti tra le app
incollando in questo caso.
Puoi accedere all'oggetto ClipEntry facendo riferimento all'attributo clipEntry.
Un oggetto ClipEntry può avere diversi oggetti ClipData.Item
quando l'utente seleziona più immagini e le copia negli appunti
ad esempio.
Devi contrassegnare come consumato o ignorato ogni oggetto ClipData.Item e restituire un TransferableContent contenente gli oggetti ClipData.Item ignorati in modo che il modificatore contentReceiver dell'antenato più vicino possa riceverlo.
Il metodo TransferableContent.hasMediaType() può aiutarti a determinare
se l'oggetto TransferableContent può fornire un elemento
con il tipo di media.
Ad esempio, la seguente chiamata al metodo restituisce true se l'oggetto TransferableContent può fornire un'immagine.
transferableContent.hasMediaType(MediaType.Image)
Utilizzare dati complessi
Puoi copiare dati complessi negli appunti nello stesso modo in cui fai per i contenuti avanzati. Per maggiori dettagli, consulta Utilizzare i provider di contenuti per copiare dati complessi.
Puoi anche gestire l'incollatura di dati complessi nello stesso modo per i contenuti avanzati.
Puoi ricevere un URI dei dati incollati.
I dati effettivi possono essere recuperati da un ContentProvider.
Per maggiori informazioni, consulta Recuperare i dati dal provider.
Feedback sulla copia dei contenuti
Gli utenti si aspettano un feedback quando copiano contenuti negli appunti, quindi, oltre al framework che gestisce la copia e l'incollatura, Android mostra un'UI predefinita agli utenti quando copiano in Android 13 (livello API 33) e versioni successive. A causa di questa funzionalità, esiste il rischio di notifiche duplicate. Puoi scoprire di più su questo caso limite in Evitare notifiche duplicate.
Fornisci manualmente feedback agli utenti quando copiano in Android 12L (livello API 32) e versioni precedenti. Consulta la raccomandazione.
Contenuti sensibili
Se scegli di consentire alla tua app di copiare contenuti sensibili negli appunti, ad esempio le password, la tua app deve comunicarlo al sistema in modo che possa evitare di visualizzare i contenuti sensibili copiati nell'UI (Figura 2).
Devi aggiungere un flag a ClipDescription in ClipData
prima di chiamare il metodo setClip() sull'oggetto 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) } }