在多窗口模式下拖放
使用集合让一切井井有条
根据您的偏好保存内容并对其进行分类。
搭载 Android 7.0(API 级别 24)或更高版本的设备支持多窗口模式
模式,这让用户可以
通过拖放的方式将数据从一个应用移到另一个应用。
源应用(操作开始的地方)提供数据。
操作结束的目标应用接收数据。
当用户开始拖动内容时,源应用应设置
将 DRAG_FLAG_GLOBAL
标志设置为
表示用户可以将数据拖动到另一个应用。
由于数据是跨应用边界移动,因此应用会共享对数据的访问权限
使用内容 URI这需要满足以下条件:
- 源应用必须设置
DRAG_FLAG_GLOBAL_URI_READ
和
DRAG_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;
});
本页面上的内容和代码示例受内容许可部分所述许可的限制。Java 和 OpenJDK 是 Oracle 和/或其关联公司的注册商标。
最后更新时间 (UTC):2025-07-27。
[null,null,["最后更新时间 (UTC):2025-07-27。"],[],[],null,["# Drag and drop in multi-window mode\n\nDevices that run Android 7.0 (API level 24) or higher support [multi-window\nmode](/develop/ui/views/layout/support-multi-window-mode), which lets users\nmove data from one app to another by dragging and dropping.\n\nThe *source app* , where the operation starts, provides the data.\nThe *target app*, where the operation ends, receives the data.\n\nWhen the user starts to drag content, the source app should set the\n[`DRAG_FLAG_GLOBAL`](/reference/android/view/View#DRAG_FLAG_GLOBAL) flag to\nindicate that the user can drag data to another app.\n\nBecause the data moves across app boundaries, the apps share access to the data\nusing a content URI. This requires the following:\n\n- The source app must set either or both of the [`DRAG_FLAG_GLOBAL_URI_READ`](/reference/android/view/View#DRAG_FLAG_GLOBAL_URI_READ) and [`DRAG_FLAG_GLOBAL_URI_WRITE`](/reference/android/view/View#DRAG_FLAG_GLOBAL_URI_WRITE) flags, depending on the read or write access to the data that the source app wants to grant to the target app.\n- The target app must call [`requestDragAndDropPermissions()`](/reference/android/app/Activity#requestDragAndDropPermissions(android.view.DragEvent)) immediately before handling the data that the user drags into the app. If the target app no longer needs access to the dragged data, the app can then call [`release()`](/reference/android/view/DragAndDropPermissions#release()) on the object that was returned from `requestDragAndDropPermissions()`. Otherwise, the permissions are released when the containing activity is destroyed. If your implementation involves starting a new Activity to process the dropped URIs, you will need to grant the new Activity the same permissions. You must set the clip data and a flag: \n\n ### Kotlin\n\n ```kotlin\n intent.setClipData(clipData)\n intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)\n ```\n\n ### Java\n\n ```java\n intent.setClipData(clipData);\n intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);\n ```\n\nThe following code snippets demonstrate how to release read-only access to\ndragged data immediately after the user drop operation takes place. See the\n[Drag and Drop Demo](https://github.com/android/user-interface-samples/tree/main/DragAndDrop)\non GitHub for a more complete example.\n\nSource activity\n---------------\n\n### Kotlin\n\n```kotlin\n// Drag a file stored in an images/ directory in internal storage.\nval internalImagesDir = File(context.filesDir, \"images\")\nval imageFile = File(internalImagesDir, imageFilename)\nval uri = FileProvider.getUriForFile(context, contentAuthority, imageFile)\n\nval listener = OnDragStartListener@{ view: View, _: DragStartHelper -\u003e\n val clipData = ClipData(ClipDescription(\"Image Description\",\n arrayOf(\"image/*\")),\n ClipData.Item(uri))\n // Must include DRAG_FLAG_GLOBAL to permit dragging data between apps.\n // This example provides read-only access to the data.\n val flags = View.DRAG_FLAG_GLOBAL or View.DRAG_FLAG_GLOBAL_URI_READ\n return@OnDragStartListener view.startDragAndDrop(clipData,\n View.DragShadowBuilder(view),\n null,\n flags)\n}\n\n// Container where the image originally appears in the source app.\nval srcImageView = findViewById\u003cImageView\u003e(R.id.imageView)\n\n// Detect and start the drag event.\nDragStartHelper(srcImageView, listener).apply {\n attach()\n}\n```\n\n### Java\n\n```java\n// Drag a file stored in an images/ directory in internal storage.\nFile internalImagesDir = new File(context.getFilesDir(), \"images\");\nFile imageFile = new File(internalImagesDir, imageFilename);\nfinal Uri uri = FileProvider.getUriForFile(context, contentAuthority, imageFile);\n\n// Container where the image originally appears in the source app.\nImageView srcImageView = findViewById(R.id.imageView);\n\n// Enable the view to detect and start the drag event.\nnew DragStartHelper(srcImageView, (view, helper) -\u003e {\n ClipData clipData = new ClipData(new ClipDescription(\"Image Description\",\n new String[] {\"image/*\"}),\n new ClipData.Item(uri));\n // Must include DRAG_FLAG_GLOBAL to permit dragging data between apps.\n // This example provides read-only access to the data.\n int flags = View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ;\n return view.startDragAndDrop(clipData,\n new View.DragShadowBuilder(view),\n null,\n flags);\n}).attach();\n```\n\nTarget activity\n---------------\n\n### Kotlin\n\n```kotlin\n// Container where the image is to be dropped in the target app.\nval targetImageView = findViewById\u003cImageView\u003e(R.id.imageView)\n\ntargetImageView.setOnDragListener { view, event -\u003e\n\n when (event.action) {\n\n ACTION_DROP -\u003e {\n val imageItem: ClipData.Item = event.clipData.getItemAt(0)\n val uri = imageItem.uri\n\n // Request permission to access the image data being dragged into\n // the target activity's ImageView element.\n val dropPermissions = requestDragAndDropPermissions(event)\n (view as ImageView).setImageURI(uri)\n\n // Release the permission immediately afterward because it's no\n // longer needed.\n dropPermissions.release()\n return@setOnDragListener true\n }\n\n // Implement logic for other DragEvent cases here.\n\n // An unknown action type is received.\n else -\u003e {\n Log.e(\"DragDrop Example\", \"Unknown action type received by View.OnDragListener.\")\n return@setOnDragListener false\n }\n\n }\n}\n```\n\n### Java\n\n```java\n// Container where the image is to be dropped in the target app.\nImageView targetImageView = findViewById(R.id.imageView);\n\ntargetImageView.setOnDragListener( (view, event) -\u003e {\n\n switch (event.getAction()) {\n\n case ACTION_DROP:\n ClipData.Item imageItem = event.getClipData().getItemAt(0);\n Uri uri = imageItem.getUri();\n\n // Request permission to access the image data being dragged into\n // the target activity's ImageView element.\n DragAndDropPermissions dropPermissions =\n requestDragAndDropPermissions(event);\n\n ((ImageView)view).setImageURI(uri);\n\n // Release the permission immediately afterward because it's no\n // longer needed.\n dropPermissions.release();\n\n return true;\n\n // Implement logic for other DragEvent cases here.\n\n // An unknown action type was received.\n default:\n Log.e(\"DragDrop Example\",\"Unknown action type received by View.OnDragListener.\");\n break;\n }\n\n return false;\n});\n```"]]