کشیدن و رها کردن در حالت چندپنجره‌ای

دستگاه‌هایی که Android نسخه ۷.۰ (سطح میانای برنامه‌سازی کاربردی ۲۴) یا بالاتر دارند از حالت چندپنجره‌ای پشتیبانی می‌کنند که به کاربران اجازه می‌دهد داده‌ها را با کشیدن و رها کردن از برنامه‌ای به برنامه دیگر منتقل کنند.

برنامه منبع، جایی که عملیات شروع می‌شود، داده‌ها را ارائه می‌دهد. برنامه هدف، جایی که عملیات به‌پایان می‌رسد، داده‌ها را دریافت می‌کند.

وقتی کاربر شروع به کشیدن محتوا می‌کند، برنامه منبع باید پرچم DRAG_FLAG_GLOBAL را تنظیم کند تا نشان دهد کاربر می‌تواند داده‌ها را به برنامه دیگری بکشد.

چون داده‌ها از مرزهای برنامه عبور می‌کنند، برنامه‌ها دسترسی به داده‌ها را بااستفاده از شناسه منبع یکسان محتوا هم‌رسانی می‌کنند. این کار به موارد زیر نیاز دارد:

  • برنامه منبع باید یکی یا هر دو پرچم DRAG_FLAG_GLOBAL_URI_READ و DRAG_FLAG_GLOBAL_URI_WRITE را بسته به دسترسی خواندن یا نوشتن به داده‌هایی که برنامه منبع می‌خواهد به برنامه هدف اعطا کند، تنظیم کند.
  • برنامه هدف باید requestDragAndDropPermissions() را بلافاصله قبل‌از مدیریت داده‌هایی که کاربر به برنامه می‌کشد فراخوانی کند. اگر برنامه هدف دیگر نیازی به دسترسی به داده‌های کشیده‌شده نداشته باشد، برنامه می‌تواند release() را در شیء برگردانده‌شده از requestDragAndDropPermissions() فراخوانی کند. درغیراین‌صورت، وقتی فعالیت حاوی آن ازبین برود، اجازه‌ها آزاد می‌شوند. اگر پیاده‌سازی شما شامل شروع یک «فعالیت» جدید برای پردازش URIهای رهاشده باشد، باید همان اجازه‌ها را به «فعالیت» جدید اعطا کنید. باید داده‌های کلیپ و پرچم را تنظیم کنید:

    کاتلین

    intent.setClipData(clipData)
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)

    جاوا

    intent.setClipData(clipData);
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

تکه‌کدهای زیر نشان می‌دهند که چگونه می‌توان دسترسی فقط خواندنی به داده‌های کشیده‌شده را بلافاصله پس‌از انجام عملیات رها کردن توسط کاربر آزاد کرد. برای دیدن نمونه کامل‌تر، نمونه نمایشی کشیدن و رها کردن را در GitHub ببینید.

فعالیت منبع

کاتلین

// Drag a file stored in an images/ directory in internal storage.
val internalImagesDir = File(context.filesDir, "images")
val imageFile = File(internalImagesDir, imageFilename)
val uri = FileProvider.getUriForFile(context, contentAuthority, imageFile)

val listener = OnDragStartListener@{ view: View, _: DragStartHelper ->
    val clipData = ClipData(ClipDescription("Image Description",
                                            arrayOf("image/*")),
                            ClipData.Item(uri))
    // Must include DRAG_FLAG_GLOBAL to permit dragging data between apps.
    // This example provides read-only access to the data.
    val flags = View.DRAG_FLAG_GLOBAL or View.DRAG_FLAG_GLOBAL_URI_READ
    return@OnDragStartListener view.startDragAndDrop(clipData,
                                                     View.DragShadowBuilder(view),
                                                     null,
                                                     flags)
}

// Container where the image originally appears in the source app.
val srcImageView = findViewById<ImageView>(R.id.imageView)

// Detect and start the drag event.
DragStartHelper(srcImageView, listener).apply {
    attach()
}

جاوا

// Drag a file stored in an images/ directory in internal storage.
File internalImagesDir = new File(context.getFilesDir(), "images");
File imageFile = new File(internalImagesDir, imageFilename);
final Uri uri = FileProvider.getUriForFile(context, contentAuthority, imageFile);

// Container where the image originally appears in the source app.
ImageView srcImageView = findViewById(R.id.imageView);

// Enable the view to detect and start the drag event.
new DragStartHelper(srcImageView, (view, helper) -> {
    ClipData clipData = new ClipData(new ClipDescription("Image Description",
                                                          new String[] {"image/*"}),
                                     new ClipData.Item(uri));
    // Must include DRAG_FLAG_GLOBAL to permit dragging data between apps.
    // This example provides read-only access to the data.
    int flags = View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ;
    return view.startDragAndDrop(clipData,
                                 new View.DragShadowBuilder(view),
                                 null,
                                 flags);
}).attach();

فعالیت هدف

کاتلین

// Container where the image is to be dropped in the target app.
val targetImageView = findViewById<ImageView>(R.id.imageView)

targetImageView.setOnDragListener { view, event ->

    when (event.action) {

        ACTION_DROP -> {
            val imageItem: ClipData.Item = event.clipData.getItemAt(0)
            val uri = imageItem.uri

            // Request permission to access the image data being dragged into
            // the target activity's ImageView element.
            val dropPermissions = requestDragAndDropPermissions(event)
            (view as ImageView).setImageURI(uri)

            // Release the permission immediately afterward because it's no
            // longer needed.
            dropPermissions.release()
            return@setOnDragListener true
        }

        // Implement logic for other DragEvent cases here.

        // An unknown action type is received.
        else -> {
            Log.e("DragDrop Example", "Unknown action type received by View.OnDragListener.")
            return@setOnDragListener false
        }

    }
}

جاوا

// Container where the image is to be dropped in the target app.
ImageView targetImageView = findViewById(R.id.imageView);

targetImageView.setOnDragListener( (view, event) -> {

    switch (event.getAction()) {

        case ACTION_DROP:
            ClipData.Item imageItem = event.getClipData().getItemAt(0);
            Uri uri = imageItem.getUri();

            // Request permission to access the image data being dragged into
            // the target activity's ImageView element.
            DragAndDropPermissions dropPermissions =
                requestDragAndDropPermissions(event);

            ((ImageView)view).setImageURI(uri);

            // Release the permission immediately afterward because it's no
            // longer needed.
            dropPermissions.release();

            return true;

        // Implement logic for other DragEvent cases here.

        // An unknown action type was received.
        default:
            Log.e("DragDrop Example","Unknown action type received by View.OnDragListener.");
            break;
    }

    return false;
});