Il framework Android basato sugli appunti per copiare e incollare supporta tipi di dati primitivi e complessi, tra cui:
- Stringhe di testo
- Strutture di dati complesse
- Dati dei flussi di testo e binari
- Asset dell'applicazione
Semplici dati di testo vengono memorizzati direttamente negli appunti, mentre i dati complessi sono archiviati come riferimento che l'applicazione incollata venga risolta con un fornitore di contenuti.
Il copia e incolla funziona sia all'interno di un'applicazione sia tra applicazioni che implementano il framework.
Poiché parte del framework utilizza fornitori di contenuti, In questo documento si presume una certa familiarità con l'API Android Content Provider.
Lavora con il testo
Alcuni componenti supportano la copia e l'incollaggio del testo, come mostrato nella tabella seguente.
Componente | Copiare testo | Incollare testo |
---|---|---|
BasicTextField | ✅ | ✅ |
TextField | ✅ | ✅ |
Contenitore di selezione | ✅ |
Ad esempio, puoi copiare il testo della scheda negli appunti nel seguente snippet e incollarlo in TextField
.
Viene visualizzato il menu per incollare il testo tramite
tocca e Tieni premuto il pulsante TextField
o tocca il punto di manipolazione 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 informazioni dettagliate, consulta Gestire le azioni della tastiera.
Copia con ClipboardManager
Puoi copiare i testi negli appunti con ClipboardManager
.
Il metodo setText() copiato
l'oggetto String passato negli appunti.
Il seguente snippet copia "Un saluto da ClipBoard"
nella clipboard 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("Hello, clipboard")
}
) {
Text("Click to copy a text")
}
Il seguente snippet fa la stessa cosa, ma fornisce 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 oggetto ClipData
che descrive i dati negli appunti.
Il metodo ClipData.newPlainText()
è un metodo di utilità per creare un oggetto ClipData
da un oggetto String.
Puoi impostare l'oggetto ClipEntry
creato negli appunti
chiamando il metodo setClip()
sopra l'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")
}
Incolla con ClipboardManager
Puoi accedere al testo copiato negli appunti chiamando il metodo getText()
su ClipboardManager
.
Il suo 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
.
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")
}
}
Lavorare con 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 consente di implementare l'inserimento di contenuti avanzati.
Copiare i contenuti avanzati
La tua app non può copiare i contenuti avanzati direttamente negli appunti.
L'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 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'inserimento 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 oggetti 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)
)
Il modificatore contentReceiver
prende un oggetto ReceiveContentListener
come argomento e chiama onReceive
dell'oggetto passato quando l'utente incolla i dati
al BasicTextField
all'interno del componente modificato.
Un oggetto TransferableContent
viene passato al metodo onReceive,
che descrive i dati che è possibile trasferire 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 diverse immagini e le copia negli appunti
ad esempio.
Devi contrassegnare come consumato o ignorato per ogni oggetto ClipData.Item
.
e restituirà un valore TransferableContent
contenente
gli oggetti ClipData.Item
ignorati
in modo che possa ricevere il modificatore contentReceiver
predecessore più vicino.
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)
Lavorare con dati complessi
Puoi copiare dati complessi negli appunti esattamente come per i contenuti avanzati. Per maggiori dettagli, consulta Utilizzare i fornitori di contenuti per copiare dati complessi.
Puoi anche gestire le incollature di dati complessi allo stesso modo per i contenuti avanzati.
Puoi ricevere un URI dei dati incollati.
I dati effettivi possono essere recuperati da un ContentProvider
.
Per ulteriori informazioni, consulta Recupero dei dati dal fornitore.
Feedback per la copia dei contenuti
Gli utenti si aspettano un feedback quando copiano i contenuti nella clipboard, quindi, oltre al framework che supporta la funzionalità di copia e incolla, Android mostra agli utenti un'interfaccia utente predefinita quando eseguono la copia in Android 13 (livello API 33) e versioni successive. A causa di questa funzionalità, esiste il rischio di una notifica duplicata. Puoi scoprire di più su questo caso limite nell'articolo Evitare le notifiche duplicate.
Fornire feedback agli utenti manualmente durante la copia in Android 12L (livello API 32) e versioni precedenti. Leggi il consiglio.
Contenuti sensibili
Se scegli di consentire all'utente di copiare contenuti sensibili nella clipboard, come le password, la tua app deve comunicarlo al sistema in modo che possa evitare di visualizzare i contenuti sensibili copiati nell'interfaccia utente (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)
}
}