在多窗口模式下拖放

搭载 Android 7.0(API 级别 24)或更高版本的设备支持多窗口模式 模式,这让用户可以 通过拖放的方式将数据从一个应用移到另一个应用。

源应用(操作开始的地方)提供数据。 操作结束的目标应用接收数据。

当用户开始拖动内容时,源应用应设置 将 DRAG_FLAG_GLOBAL 标志设置为 表示用户可以将数据拖动到另一个应用。

由于数据是跨应用边界移动,因此应用会共享对数据的访问权限 使用内容 URI这需要满足以下条件:

  • 源应用必须设置 DRAG_FLAG_GLOBAL_URI_READDRAG_FLAG_GLOBAL_URI_WRITE 标志,具体取决于源应用 希望授予目标应用的权限。
  • 目标应用必须调用 requestDragAndDropPermissions() 处理用户拖入应用的数据之前。如果 目标应用不再需要访问拖动的数据, 然后调用 release()已开启 从 requestDragAndDropPermissions() 返回的对象。 否则,当包含的 activity 被触发时, 已销毁。 如果您的实现涉及启动一个新 activity 来处理 被丢弃的 URI,您将需要向新 Activity 授予相同的权限。 您必须设置剪辑数据和标志:

    Kotlin

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

    Java

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

以下代码段演示了如何释放对 用户放下操作发生后立即拖动数据。请参阅 拖放演示 获取更完整的示例。

来源活动

Kotlin

// 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() }

Java

// 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();

目标活动

Kotlin

// 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  }  } }

Java

// 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; });