کپی و پیست کنید

چارچوب مبتنی بر کلیپ بورد اندروید برای کپی و چسباندن از انواع داده های ابتدایی و پیچیده پشتیبانی می کند، از جمله:

  • رشته های متنی
  • ساختارهای داده پیچیده
  • متن و داده های جریان باینری
  • دارایی های کاربردی

داده‌های متنی ساده مستقیماً در کلیپ بورد ذخیره می‌شوند، در حالی که داده‌های پیچیده به عنوان مرجع ذخیره می‌شوند که برنامه چسباندن آن را با ارائه‌دهنده محتوا حل می‌کند.

کپی و چسباندن هم در یک برنامه کاربردی و هم بین برنامه هایی که فریم ورک را پیاده سازی می کنند کار می کند.

از آنجایی که بخشی از چارچوب از ارائه‌دهندگان محتوا استفاده می‌کند، این سند آشنایی با 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 اطلاعات بیشتری کسب کنید.

انیمیشنی که اعلان کلیپ بورد اندروید 13 را نشان می دهد
شکل 1. رابط کاربری زمانی که محتوا وارد کلیپ بورد در اندروید 13 و بالاتر می شود نشان داده شده است.

هنگام کپی کردن در Android 12L (سطح API 32) و پایین‌تر، بازخورد را به صورت دستی به کاربران ارائه دهید. توصیه را ببینید.

محتوای حساس

اگر می‌خواهید برنامه‌تان به کاربر اجازه دهد محتوای حساس را در کلیپ‌بورد کپی کند، مانند گذرواژه‌ها، برنامه شما باید به سیستم اطلاع دهد تا سیستم بتواند از نمایش محتوای حساس کپی شده در رابط کاربری خودداری کند (شکل 2).

پیش‌نمایش متن کپی شده پرچم‌گذاری محتوای حساس.
شکل 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)
    }
}