用於複製及貼上的 Android 剪貼簿架構 支援原始和複雜的資料類型,包括:
- 文字字串
- 複雜的資料結構
- 文字和二進位串流資料
- 應用程式素材資源
簡單文字資料會直接儲存在剪貼簿中。 並將複雜資料儲存為參考資源 執行貼上操作的應用程式會解析內容供應器
複製及貼上功能可在應用程式和應用程式之間使用 實作這個架構的
由於該架構的一部分使用內容供應器,因此本文件假設您對 Android 內容供應器 API 有一定程度的瞭解。
處理文字
部分元件支援複製及貼上文字,如下表所示。
元件 | 複製文字 | 貼上文字 |
---|---|---|
BasicTextField | ✅ | ✅ |
文字欄位 | ✅ | ✅ |
SelectContainer | ✅ |
例如,你可以將資訊卡中的文字複製到剪貼簿
貼在下列程式碼片段中,並將複製的文字貼到 TextField
。
您可以依照
觸控和按住 TextField
,或輕觸遊標控點。
val textFieldState = rememberTextFieldState()
Column {
Card {
SelectionContainer {
Text("You can copy this text")
}
}
BasicTextField(state = textFieldState)
}
你可以使用下列鍵盤快速鍵貼上文字: Ctrl + V 鍵。 根據預設,您也可以使用鍵盤快速鍵。 詳情請參閱「處理鍵盤動作」。
使用「ClipboardManager
」複製
你可以使用 ClipboardManager
將文字複製到剪貼簿。
其 setText() 方法會複製
傳遞到剪貼簿的 String 物件
當使用者按下按鈕時,下列程式碼片段會將「Hello, clipboard」複製到剪貼簿。
// 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")
}
以下程式碼片段可執行相同的操作,但可讓您更精細地控管。常見用途是複製敏感內容,例如密碼。ClipEntry
會說明剪貼簿中的項目。其中包含 ClipData
物件,可說明剪貼簿中的資料。ClipData.newPlainText()
方法是便利方法,可從 String 物件建立 ClipData
物件。您可以將已建立的 ClipEntry
物件設為剪貼簿
呼叫 setClip() 方法
放在 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")
}
使用 ClipboardManager 貼上
您可以透過 ClipboardManager
呼叫 getText()
方法,存取複製到剪貼簿的文字。當文字複製到剪貼簿時,其 getText()
方法會傳回 AnnotatedString
物件。下列程式碼片段會將剪貼簿中的文字附加至 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")
}
}
使用多媒體內容
使用者喜歡圖片、影片和其他生動的內容。您的應用程式可讓使用者透過 ClipboardManager
和 ClipEntry
複製富內容。contentReceiver
修飾符可協助您實作多媒體內容。
複製多媒體內容
您的應用程式無法直接將富內容複製到剪貼簿。相反地,應用程式會將 URI
物件傳遞至剪貼簿,並透過 ContentProvider
提供內容存取權。以下程式碼片段說明如何將 JPEG 圖片複製到剪貼簿。詳情請參閱「複製資料串流」一文。
// 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")
}
貼上多媒體內容
您可以使用 contentReceiver
修飾符,在修飾的元件中處理將複製內容貼到 BasicTextField
的情況。下列程式碼片段會新增圖片資料貼上的 URI
加入 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)
)
contentReceiver
修飾符會將 ReceiveContentListener
物件做為引數,並在使用者將資料貼到修改後元件中的 BasicTextField
時,呼叫傳遞物件的 onReceive
方法。
TransferableContent
物件會傳遞至 onReceive 方法,該方法會描述可透過貼上方式在應用程式之間傳輸的資料。您可以透過參照 clipEntry
屬性來存取 ClipEntry
物件。
ClipEntry
物件可能有多個 ClipData.Item
物件
使用者選取多張圖片並複製到剪貼簿時
例如
您應為每個 ClipData.Item
物件標示已使用或已略過,並傳回包含已略過 ClipData.Item
物件的 TransferableContent
,以便最接近的祖系 contentReceiver
修飾符能夠接收。
TransferableContent.hasMediaType()
方法可協助您判斷 TransferableContent
物件是否能提供具有媒體類型的項目。舉例來說,如果 TransferableContent
物件可以提供圖片,則下列方法呼叫會傳回 true
。
transferableContent.hasMediaType(MediaType.Image)
處理複雜資料
你可以將複雜資料複製到剪貼簿 和多媒體內容一樣 詳情請參閱「使用內容供應器複製複雜資料」。
您也可以將複雜的資料貼上處理
以符合多媒體內容的形式
您可以接收貼上資料的 URI。您可以從 ContentProvider
擷取實際資料。詳情請參閱「從供應商擷取資料」一文。
複製內容的意見回饋
使用者希望能在複製內容到剪貼簿時獲得回饋。 除了開發複製及貼上功能的架構之外 使用者在 Android 13 (API 級別 33) 中複製內容時,Android 會顯示預設 UI 以及更高版本由於這項功能的緣故,因此可能會有重複通知的風險。 如要進一步瞭解這個極端情況,請參閱「避免重複通知」。
在 Android 12L (API 級別 32) 以下版本中複製內容時,請手動向使用者提供回饋。請參閱建議做法。
敏感內容
如果您選擇讓應用程式允許使用者將敏感內容 (例如密碼) 複製到剪貼簿,則應用程式必須通知系統,以免系統在 UI 中顯示複製的敏感內容 (圖 2)。
您必須在 ClipData
中將標記新增至 ClipDescription
再透過 ClipboardManager
物件呼叫 setClip()
方法:
// 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)
}
}