המסגרת של Android להעתקה והדבקה באמצעות הלוח תומכת בסוגי נתונים פרימיטיביים ומורכבים, כולל:
- מחרוזות טקסט
- מבני נתונים מורכבים
- נתוני סטרימינג בפורמט טקסט ובינארי
- נכסי אפליקציות
נתוני טקסט פשוטים נשמרים ישירות בלוח, ונתונים מורכבים נשמרים כהפניה שהאפליקציה שבה מדביקים פותרת באמצעות ספק לניהול גישה.
אפשר להעתיק ולהדביק בתוך אפליקציה ובין אפליקציות שמטמיעות את המסגרת.
חלק מה-Framework משתמש בספקי תוכן, ולכן במאמר הזה אנחנו מניחים שיש לכם היכרות מסוימת עם Android Content Provider API.
עבודה עם טקסט
חלק מהרכיבים תומכים בהעתקה והדבקה של טקסט מחוץ לקופסה, כמו שמוצג בטבלה הבאה.
| רכיב | העתקת טקסט | הדבקת טקסט |
|---|---|---|
| BasicTextField | ✅ | ✅ |
| TextField | ✅ | ✅ |
| SelectionContainer | ✅ |
לדוגמה, אפשר להעתיק את הטקסט בכרטיס ללוח
ההדבקה בקטע הקוד הבא ולהדביק את הטקסט שהועתק ב-TextField.
כדי להציג את התפריט להדבקת הטקסט, לוחצים לחיצה ארוכה על TextField או מקישים על ידית הסמן.
val textFieldState = rememberTextFieldState() Column { Card { SelectionContainer { Text("You can copy this text") } } BasicTextField(state = textFieldState) }
אפשר להדביק את הטקסט באמצעות מקש הקיצור הבא: Ctrl+V . מקשי הקיצור זמינים גם הם כברירת מחדל. פרטים נוספים זמינים במאמר בנושא טיפול בפעולות במקלדת.
העתקה באמצעות ClipboardManager
אתם יכולים להעתיק טקסטים ללוח באמצעות ClipboardManager.
השיטה setText() מעתיקה את האובייקט AnnotatedString שהועבר ללוח.
קטע הקוד הבא מעתיק את המחרוזת Hello, clipboard ללוח כשהמשתמש לוחץ על הלחצן.
// 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") }
קטע הקוד הבא מבצע את אותה פעולה, אבל נותן לכם שליטה מפורטת יותר.
תרחיש נפוץ לשימוש הוא העתקת תוכן רגיש, כמו סיסמה. ClipEntry מתאר פריט בלוח.
הוא מכיל אובייקט ClipData שמתאר את הנתונים בלוח.
השיטה ClipData.newPlainText() היא שיטה נוחה ליצירת אובייקט ClipData מאובייקט String.
כדי להגדיר את האובייקט ClipEntry שנוצר ללוח, צריך להפעיל את ה-method 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
כדי לגשת לטקסט שהועתק ללוח, צריך להפעיל את ה-method getText() דרך ClipboardManager.
השיטה getText() מחזירה אובייקט AnnotatedString כשטקסט מועתק ללוח.
קטע הקוד הבא מוסיף את הטקסט שבלוח לטקסט שב-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") } }
עבודה עם תוכן עשיר
המשתמשים אוהבים תמונות, סרטונים ותוכן אחר שמעביר רגשות.
האפליקציה יכולה לאפשר למשתמש להעתיק תוכן עשיר באמצעות 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 = 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) )
המשנה contentReceiver מקבל אובייקט ReceiveContentListener כארגומנט ומפעיל את השיטה onReceive של האובייקט שהועבר כשהמשתמש מדביק נתונים ל-BasicTextField בתוך הרכיב ששונה.
אובייקט TransferableContent מועבר לשיטה onReceive, שמתארת את הנתונים שאפשר להעביר בין אפליקציות באמצעות הדבקה במקרה הזה.
אפשר לגשת לאובייקט ClipEntry באמצעות הפנייה למאפיין clipEntry.
לאובייקט ClipEntry יכולים להיות כמה אובייקטים מסוג ClipData.Item, למשל כשמשתמש בוחר כמה תמונות ומעתיק אותן ללוח.
צריך לסמן כל אובייקט ClipData.Item כ'נצרך' או כ'התעלמות', ולהחזיר אובייקט TransferableContent שמכיל את האובייקטים ClipData.Item שהמערכת התעלמה מהם, כדי שהמשנה contentReceiver של האב הקרוב ביותר יוכל לקבל אותו.
השיטה TransferableContent.hasMediaType() יכולה לעזור לכם לקבוע אם האובייקט TransferableContent יכול לספק פריט עם סוג המדיה.
לדוגמה, הפעלת method הבאה מחזירה true אם האובייקט TransferableContent יכול לספק תמונה.
transferableContent.hasMediaType(MediaType.Image)
עבודה עם נתונים מורכבים
אתם יכולים להעתיק נתונים מורכבים ללוח באותו אופן שבו אתם מעתיקים תוכן עשיר. פרטים נוספים זמינים במאמר שימוש בספקים לניהול גישה כדי להעתיק נתונים מורכבים.
אפשר גם לטפל בהדבקות של נתונים מורכבים באותו אופן עבור התוכן העשיר.
אתם יכולים לקבל URI של הנתונים שהודבקו.
אפשר לאחזר את הנתונים בפועל מ-ContentProvider.
מידע נוסף זמין בקטע אחזור נתונים מהספק.
משוב על העתקת תוכן
המשתמשים מצפים לקבל משוב כשהם מעתיקים תוכן ללוח, אז בנוסף למסגרת שמפעילה את ההעתקה וההדבקה, Android מציגה ממשק משתמש כברירת מחדל למשתמשים כשהם מעתיקים ב-Android בגרסה 13 (רמת API 33) ומעלה. בגלל התכונה הזו, יש סיכון לשליחת התראה כפולה. מידע נוסף על מקרה הקצה הזה זמין במאמר איך למנוע התראות כפולות.
לספק משוב למשתמשים באופן ידני כשמעתיקים ב-Android 12L (רמת API 32) ומטה. להמלצה
תוכן רגיש
אם בחרתם שהאפליקציה תאפשר למשתמש להעתיק תוכן רגיש ללוח, כמו סיסמאות, האפליקציה צריכה להודיע למערכת כדי שהמערכת תוכל להימנע מהצגת התוכן הרגיש שהועתק בממשק המשתמש (איור 2).
צריך להוסיף דגל ל-ClipDescription ב-ClipData לפני שקוראים לשיטה setClip() באובייקט 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) } }