Platforma kopiowania i wklejania oparta na schowku Androida obsługuje proste i złożone typy danych, w tym:
- ciągi tekstowe,
- złożone struktury danych,
- dane tekstowe i binarne,
- komponenty aplikacji.
Proste dane tekstowe są przechowywane bezpośrednio w schowku, a złożone dane są przechowywane jako odniesienie, które aplikacja wklejająca rozwiązuje za pomocą dostawcy treści.
Kopiowanie i wklejanie działa zarówno w obrębie aplikacji, jak i między aplikacjami, które implementują platformę.
Ponieważ część platformy korzysta z dostawców treści, w tym dokumencie zakłada się, że masz pewną wiedzę na temat interfejsu Android Content Provider API.
Praca z tekstem
Niektóre komponenty obsługują kopiowanie i wklejanie tekstu od razu po zainstalowaniu, jak pokazano w tabeli poniżej.
| Komponent | Kopiowanie tekstu | Wklejanie tekstu |
|---|---|---|
| BasicTextField | ✅ | ✅ |
| TextField | ✅ | ✅ |
| SelectionContainer | ✅ |
Na przykład w tym fragmencie kodu możesz skopiować tekst z karty do schowka i wkleić go do TextField.
Aby wyświetlić menu wklejania tekstu, dotknij i przytrzymaj TextField lub naciśnij uchwyt kursora.
val textFieldState = rememberTextFieldState() Column { Card { SelectionContainer { Text("You can copy this text") } } BasicTextField(state = textFieldState) }
Tekst możesz wkleić za pomocą skrótu klawiszowego: Ctrl+V . Skrót klawiszowy jest też domyślnie dostępny. Więcej informacji znajdziesz w artykule Obsługa działań klawiatury.
Kopiowanie za pomocą ClipboardManager
Tekst możesz kopiować do schowka za pomocą ClipboardManager.
Metoda setText() kopiuje
przekazany obiekt AnnotatedString do schowka.
Ten fragment kodu kopiuje do schowka tekst „Hello, clipboard”, gdy użytkownik kliknie przycisk.
// 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") }
Ten fragment kodu robi to samo, ale daje większą kontrolę.
Częstym przypadkiem użycia jest kopiowanie treści o charakterze kontrowersyjnym,
np. hasła. ClipEntry opisuje element w schowku.
Zawiera obiekt ClipData, który opisuje dane w schowku.
ClipData.newPlainText() method is a convenience method to
create a ClipData object from a String object.
Utworzony obiekt ClipEntry możesz ustawić w schowku
wywołując metodę setClip()
na obiekcie 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") }
Wklejanie za pomocą ClipboardManager
Dostęp do tekstu skopiowanego do schowka możesz uzyskać
wywołując getText() metodę
na obiekcie ClipboardManager.
Gdy tekst zostanie skopiowany do schowka, metoda getText() zwraca obiekt AnnotatedString.
Ten fragment kodu dołącza tekst ze schowka do tekstu w 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") } }
Praca ze szczegółowymi treściami
Użytkownicy uwielbiają obrazy, filmy i inne ekspresyjne treści.
Twoja aplikacja może umożliwiać użytkownikom kopiowanie szczegółowych treści za pomocą ClipboardManager i ClipEntry.
Modyfikator contentReceiver pomaga w implementowaniu wklejania szczegółowych treści.
Kopiowanie szczegółowych treści
Twoja aplikacja nie może kopiować szczegółowych treści bezpośrednio do schowka.
Zamiast tego przekazuje do schowka obiekt URI
i zapewnia dostęp do treści za pomocą ContentProvider.
Ten fragment kodu pokazuje, jak skopiować obraz JPEG do schowka.
Więcej informacji znajdziesz w artykule Kopiowanie strumieni danych.
// 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") }
Wklejanie szczegółowych treści
Za pomocą modyfikatora contentReceiver możesz obsługiwać wklejanie szczegółowych treści
do BasicTextField w zmodyfikowanym komponencie.
Ten fragment kodu dodaje wklejony adres URI danych obrazu
do listy obiektów 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) )
Modyfikator contentReceiver przyjmuje jako argument obiekt ReceiveContentListener
i wywołuje metodę onReceive
przekazanego obiektu, gdy użytkownik wkleja dane
do BasicTextField w zmodyfikowanym komponencie.
Do metody onReceive przekazywany jest obiekt TransferableContent, który opisuje dane, które można przenosić między aplikacjami przez wklejanie.
Dostęp do obiektu ClipEntry możesz uzyskać, odwołując się do atrybutu clipEntry.
Obiekt ClipEntry może mieć kilka obiektów ClipData.Item
gdy użytkownik wybierze kilka obrazów i skopiuje je do schowka
na przykład.
Każdy obiekt ClipData.Item należy oznaczyć jako zużyty lub zignorowany i zwrócić obiekt TransferableContent zawierający zignorowane obiekty ClipData.Item, aby najbliższy przodek modyfikatora contentReceiver mógł go otrzymać.
Metoda TransferableContent.hasMediaType() może pomóc Ci określić
czy obiekt TransferableContent może udostępnić element
o danym typie multimediów.
Na przykład to wywołanie metody zwraca wartość true, jeśli obiekt TransferableContent może udostępnić obraz.
transferableContent.hasMediaType(MediaType.Image)
Praca ze złożonymi danymi
Złożone dane możesz kopiować do schowka w taki sam sposób jak szczegółowe treści. Więcej informacji znajdziesz w artykule Kopiowanie złożonych danych za pomocą dostawców treści.
Wklejanie złożonych danych możesz też obsługiwać w taki sam sposób jak wklejanie szczegółowych treści.
Możesz otrzymać adres URI wklejonych danych.
Rzeczywiste dane można pobrać z ContentProvider.
Więcej informacji znajdziesz w artykule Pobieranie danych od dostawcy.
Informacje zwrotne dotyczące kopiowania treści
Gdy użytkownicy kopiują treści do schowka, oczekują informacji zwrotnych. Dlatego oprócz platformy, która umożliwia kopiowanie i wklejanie, Android wyświetla domyślny interfejs, gdy użytkownicy kopiują treści w Androidzie 13 (poziom API 33) i nowszym. Z tego powodu istnieje ryzyko duplikowania powiadomień. Więcej informacji na ten temat znajdziesz w artykule Unikanie duplikatów powiadomień.
Gdy kopiowanie odbywa się w Androidzie 12L (poziom API 32) i starszym, informacje zwrotne musisz przekazywać użytkownikom ręcznie. Zapoznaj się z zaleceniem.
Treści o charakterze kontrowersyjnym
Jeśli zdecydujesz się umożliwić użytkownikom kopiowanie do schowka treści o charakterze kontrowersyjnym, np. haseł, Twoja aplikacja musi poinformować o tym system, aby mógł on uniknąć wyświetlania skopiowanych treści o charakterze kontrowersyjnym w interfejsie (rysunek 2).
Zanim wywołasz metodę setClip() na obiekcie ClipboardManager, musisz dodać flagę do ClipDescription w ClipData:
// 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) } }