چارچوب مبتنی بر کلیپ بورد اندروید برای کپی و چسباندن از انواع داده های ابتدایی و پیچیده پشتیبانی می کند، از جمله:
- رشته های متنی
- ساختارهای داده پیچیده
- متن و داده های جریان باینری
- دارایی های کاربردی
دادههای متنی ساده مستقیماً در کلیپ بورد ذخیره میشوند، در حالی که دادههای پیچیده به عنوان مرجع ذخیره میشوند که برنامه چسباندن آن را با ارائهدهنده محتوا حل میکند.
کپی و چسباندن هم در یک برنامه کاربردی و هم بین برنامه هایی که فریم ورک را پیاده سازی می کنند کار می کند.
از آنجایی که بخشی از چارچوب از ارائهدهندگان محتوا استفاده میکند، این سند آشنایی با API ارائهدهنده محتوای Android را فرض میکند.
با متن کار کنید
برخی از مؤلفه ها از کپی و چسباندن متن خارج از جعبه پشتیبانی می کنند، همانطور که در جدول زیر نشان داده شده است.
جزء | کپی کردن متن | چسباندن متن |
---|---|---|
BasicTextField | ✅ | ✅ |
TextField | ✅ | ✅ |
انتخاب کانتینر | ✅ |
به عنوان مثال، می توانید متن موجود در کارت را در قطعه زیر در کلیپ بورد کپی کنید و متن کپی شده را در TextField
جایگذاری کنید. برای چسباندن متن با لمس و نگه داشتن روی TextField
، یا با ضربه زدن روی دسته مکان نما، منو نمایش می دهید.
val textFieldState = rememberTextFieldState()
Column {
Card {
SelectionContainer {
Text("You can copy this text")
}
}
BasicTextField(state = textFieldState)
}
می توانید متن را با میانبر صفحه کلید زیر بچسبانید: Ctrl + V . میانبر صفحه کلید نیز به صورت پیش فرض موجود است. برای جزئیات به عملکردهای صفحه کلید Handle مراجعه کنید.
با 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()
یک روش راحت برای ایجاد یک شی ClipData
از یک شی String است. با فراخوانی متد setClip() روی شی ClipboardManager
میتوانید شی ClipEntry
ایجاد شده را به کلیپ بورد تنظیم کنید.
// 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 جایگذاری کنید
می توانید با فراخوانی متد getText()
از طریق ClipboardManager
به متن کپی شده در کلیپ بورد دسترسی پیدا کنید. متد 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
مصرف شده یا نادیده گرفته شده را علامت بزنید و یک TransferableContent
حاوی اشیاء ClipData.Item
نادیده گرفته شده را برگردانید تا نزدیکترین اصلاح کننده contentReceiver
بتواند آن را دریافت کند.
متد TransferableContent.hasMediaType()
می تواند به شما کمک کند تعیین کنید آیا شی TransferableContent
می تواند یک مورد با نوع رسانه ارائه دهد یا خیر. برای مثال، اگر شی TransferableContent
بتواند یک تصویر ارائه دهد، فراخوانی متد زیر true
را برمیگرداند.
transferableContent.hasMediaType(MediaType.Image)
با داده های پیچیده کار کنید
می توانید داده های پیچیده را به همان روشی که برای محتوای غنی انجام می دهید، در کلیپ بورد کپی کنید. برای جزئیات بیشتر به استفاده از ارائه دهندگان محتوا برای کپی کردن داده های پیچیده مراجعه کنید.
همچنین میتوانید خمیرهای دادههای پیچیده را به همان شیوه برای محتوای غنی مدیریت کنید. می توانید یک URI از داده های چسبانده شده دریافت کنید. داده های واقعی را می توان از یک ContentProvider
بازیابی کرد. برای اطلاعات بیشتر به بازیابی داده ها از ارائه دهنده مراجعه کنید.
بازخورد برای کپی کردن محتوا
کاربران هنگام کپی کردن محتوا در کلیپ بورد انتظار بازخورد دارند، بنابراین علاوه بر چارچوبی که امکان کپی و چسباندن را فراهم می کند، هنگام کپی کردن در اندروید 13 (سطح API 33) و بالاتر، اندروید یک رابط کاربری پیش فرض را به کاربران نشان می دهد. با توجه به این ویژگی، خطر اعلان تکراری وجود دارد. می توانید در مورد این edge case در Avoid duplicate notifications اطلاعات بیشتری کسب کنید.
هنگام کپی کردن در Android 12L (سطح API 32) و پایینتر، بازخورد را به صورت دستی به کاربران ارائه دهید. توصیه را ببینید.
محتوای حساس
اگر میخواهید برنامهتان به کاربر اجازه دهد محتوای حساس را در کلیپبورد کپی کند، مانند گذرواژهها، برنامه شما باید به سیستم اطلاع دهد تا سیستم بتواند از نمایش محتوای حساس کپی شده در رابط کاربری خودداری کند (شکل 2).
قبل از فراخوانی متد setClip()
روی شی ClipboardManager
باید یک پرچم به ClipDescription
در 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)
}
}