Skip to content

Commit 17cb7f9

Browse files
Merge pull request #170 from android/dnd-view
Drag and Drop using views
2 parents ce4c345 + 307b67b commit 17cb7f9

File tree

11 files changed

+263
-38
lines changed

11 files changed

+263
-38
lines changed

samples/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ Drag and drop in Compose
4242
Drag and drop to another app visible in multiwindow mode
4343
- [Drag and Drop using the RichContentReceiver](user-interface/draganddrop/src/main/java/com/example/platform/ui/draganddrop/DragAndDropRichContentReceiverFragment.kt):
4444
Using RichContentReceiverInterface for implementing Drop for rich data types
45+
- [Drag and Drop using views](user-interface/draganddrop/src/main/java/com/example/platform/ui/draganddrop/DragAndDropWithViews.kt):
46+
Drag and Drop using the views
4547
- [Editing UltraHDR](graphics/ultrahdr/src/main/java/com/example/platform/graphics/ultrahdr/edit/EditingUltraHDR.kt):
4648
This sample demonstrates editing an UltraHDR image and the resulting gainmap as well. Spatial edit operations like crop, rotate, scale are supported
4749
- [Find devices sample](connectivity/bluetooth/ble/src/main/java/com/example/platform/connectivity/bluetooth/ble/FindBLEDevicesSample.kt):

samples/user-interface/draganddrop/README.md

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
1-
# Drag and Drop
2-
3-
An android application demonstrating basic Drag and Drop functionality using the
4-
[`Jetpack Drag and Drop Library`](https://developer.android.com/jetpack/androidx/releases/draganddrop).
5-
6-
Allows for plain-text items and images to be dragged into the app. Has a plain-text item and a PNG
7-
item that can be dragged within, out of, or to a second instance of the demo.
8-
9-
Utilizes [`androidx.core`](https://developer.android.com/jetpack/androidx/releases/core)'s
10-
[`DragStartHelper`](https://developer.android.com/reference/kotlin/androidx/core/view/DragStartHelper)
11-
and [`androidx.draganddrop`](https://developer.android.com/jetpack/androidx/releases/draganddrop)'s
12-
[`DropHelper`](https://developer.android.com/reference/kotlin/androidx/draganddrop/DropHelper) to
13-
simplify the process of implementing both dragging and dropping functionality.
1+
# Drag and Drop Samples
2+
3+
The samples in this directory address various various ways of implementing Drag and Drop, along with
4+
implementation of RichContentReceiver
5+
6+
- [Drag and Drop using Views](src/main/java/com/example/platform/ui/draganddrop/DragAndDropWithViews.kt)
7+
This sample demonstrate basic implementation with onLongClickListener and implementing
8+
DragListener callback
9+
- [Drag and Drop in Multi-Window mode](src/main/java/com/example/platform/ui/draganddrop/DragAndDropMultiWindow.kt)
10+
This sample demonstrate the drag-and-drop across apps.
11+
- [Drag and Drop using DragAndDropHelper Library](src/main/java/com/example/platform/ui/draganddrop/DragAndDropWithHelper.kt)
12+
This sample uses
13+
the [`Jetpack Drag and Drop Library`](https://developer.android.com/jetpack/androidx/releases/draganddrop)
14+
to demonstrate drag-and-drop.
15+
- [Drag and Drop in compose](src/main/java/com/example/platform/ui/draganddrop/DragAndDropUsingCompose.kt)
16+
This sample showcase drag-and-drop implementation in compose.
17+
- [Accepting rich media](src/main/java/com/example/platform/ui/draganddrop/DragAndDropRichContentReceiverFragment.kt)
18+
This sample showcase how rich media can be handled using RichContentReceiver unified Api which
19+
works for drag-and-drop, keyboard and clipboard
20+
21+
> **Important:** All samples run independent of each other.
1422
1523
## License
1624

samples/user-interface/draganddrop/src/main/java/com/example/platform/ui/draganddrop/DragAndDrop.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ import androidx.core.util.component2
4040
import androidx.core.view.DragStartHelper
4141
import androidx.draganddrop.DropHelper
4242
import com.example.platform.ui.draganddrop.databinding.DragAndDropActivityBinding
43-
import com.google.android.catalog.framework.annotations.Sample
4443
import java.io.ByteArrayOutputStream
4544
import java.io.File
4645
import java.io.FileInputStream
@@ -51,11 +50,13 @@ private const val TAG = "DragDropSample"
5150
private const val MAX_LENGTH = 200
5251

5352
@RequiresApi(24)
54-
@Sample(
53+
/*@Sample(
5554
name = "Drag and Drop",
5655
description = "Demonstrates basic Drag and Drop functionality.",
5756
documentation = "https://developer.android.com/develop/ui/views/touch-and-input/drag-drop",
5857
)
58+
*/
59+
@Deprecated("The new sample include segregated examples individually for Views, DragAndDropHelper, RichContentReceiver along with Compose")
5960
class DragAndDropActivity : AppCompatActivity() {
6061

6162
private lateinit var binding: DragAndDropActivityBinding

samples/user-interface/draganddrop/src/main/java/com/example/platform/ui/draganddrop/DragAndDropFileProvider.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ package com.example.platform.ui.draganddrop
1818

1919
import androidx.core.content.FileProvider
2020

21+
@Deprecated("Along with DragAndDropActivity")
2122
class DragAndDropFileProvider: FileProvider()

samples/user-interface/draganddrop/src/main/java/com/example/platform/ui/draganddrop/DragAndDropMultiWindow.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import com.google.android.catalog.framework.annotations.Sample
3737
@Sample(
3838
name = "Drag and Drop in MultiWindow mode",
3939
description = "Drag and drop to another app visible in multiwindow mode",
40-
documentation = "",
40+
documentation = "https://developer.android.com/develop/ui/views/touch-and-input/drag-drop/multi-window",
4141
)
4242
class DragAndDropMultiWindow : Fragment(R.layout.fragment_dnd_multiwindow) {
4343
lateinit var binding: FragmentDndMultiwindowBinding
@@ -47,11 +47,11 @@ class DragAndDropMultiWindow : Fragment(R.layout.fragment_dnd_multiwindow) {
4747
super.onViewCreated(view, savedInstanceState)
4848
binding = FragmentDndMultiwindowBinding.bind(view)
4949
ConstraintSet().clone(binding.root)
50-
binding.tvGreeting.text = resources.getString(R.string.dnd_multiwindow_greeting)
51-
binding.ivSource.tag = resources.getString(R.string.source_image_url)
52-
Glide.with(this).asBitmap().load(resources.getString(R.string.source_image_url))
50+
binding.tvGreeting.text = resources.getString(R.string.multiwindow_greeting)
51+
binding.ivSource.tag = resources.getString(R.string.multi_source_image_url)
52+
Glide.with(this).asBitmap().load(resources.getString(R.string.multi_source_image_url))
5353
.into(binding.ivSource)
54-
Glide.with(this).asBitmap().load(resources.getString(R.string.target_image_url))
54+
Glide.with(this).asBitmap().load(resources.getString(R.string.multi_target_image_url))
5555
.into(binding.ivTarget)
5656
setupDrag(binding.ivSource)
5757
setupDrop(binding.ivTarget)

samples/user-interface/draganddrop/src/main/java/com/example/platform/ui/draganddrop/DragAndDropRichContentReceiverFragment.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class DragAndDropRichContentReceiverFragment : Fragment(R.layout.fragment_dnd_ri
5959
binding = FragmentDndRichcontentBinding.bind(view)
6060
ConstraintSet().clone(binding.root)
6161
val items = mutableListOf<GridItem>()
62+
// binding.tvGreeting.text = getString(R.string.rich_content_greeting)
6263
initViews(items)
6364
initDrag()
6465

@@ -125,14 +126,14 @@ class DragAndDropRichContentReceiverFragment : Fragment(R.layout.fragment_dnd_ri
125126

126127
@RequiresApi(Build.VERSION_CODES.N)
127128
fun initDrag() {
128-
Glide.with(this).asBitmap().load(getString(R.string.target_image_url))
129+
Glide.with(this).asBitmap().load(getString(R.string.rich_source_image_url))
129130
.into(binding.ivSource1)
130131
addDragStartHelperForImageView(binding.ivSource1)
131-
Glide.with(this).asBitmap().load(getString(R.string.target_image_url1))
132+
Glide.with(this).asBitmap().load(getString(R.string.rich_target_image_url))
132133
.into(binding.ivSource)
133134
addDragStartHelperForImageView(binding.ivSource)
134135

135-
binding.tvDrag.text = getString(R.string.dnd_helper_greeting)
136+
binding.tvDrag.text = getString(R.string.rich_content_greeting)
136137
addDragStartHelperForTextView(binding.tvDrag)
137138

138139
}

samples/user-interface/draganddrop/src/main/java/com/example/platform/ui/draganddrop/DragAndDropWithHelper.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,23 +49,23 @@ class DragAndDropWithHelper : Fragment(R.layout.fragment_drag_and_drop_with_help
4949
binding = FragmentDragAndDropWithHelperBinding.bind(view)
5050
ConstraintSet().clone(binding.root)
5151

52-
binding.tvGreeting.text = getString(R.string.dnd_helper_greeting)
52+
binding.tvGreeting.text = getString(R.string.helper_greeting)
5353
/*
5454
data for drag
5555
for simplicity we have considered text as a data type to drag
5656
For rich content like Image to be used as drag data type please check the sample for
5757
Drag and Drop - rich content
5858
*/
59-
binding.ivSource.tag = getString(R.string.source_image_url)
60-
Glide.with(this).asBitmap().load(getString(R.string.source_image_url))
59+
binding.ivSource.tag = getString(R.string.helper_source_image_url)
60+
Glide.with(this).asBitmap().load(getString(R.string.helper_source_image_url))
6161
.into(binding.ivSource)
62-
Glide.with(this).asBitmap().load(getString(R.string.target_image_url))
62+
Glide.with(this).asBitmap().load(getString(R.string.helper_target_image_url))
6363
.into(binding.ivTarget)
6464
setupDrag(binding.ivSource)
6565
setupDrop(binding.ivTarget)
6666
// resetting the to state before drag
6767
binding.btnReset.setOnClickListener {
68-
Glide.with(this).asBitmap().load(getString(R.string.target_image_url))
68+
Glide.with(this).asBitmap().load(getString(R.string.helper_target_image_url))
6969
.into(binding.ivTarget)
7070
}
7171
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
/*
2+
* Copyright 2023 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.platform.ui.draganddrop
18+
19+
import android.content.ClipData
20+
import android.content.ClipDescription
21+
import android.os.Build
22+
import android.os.Bundle
23+
import android.util.Log
24+
import android.view.DragEvent
25+
import android.view.View
26+
import android.widget.ImageView
27+
import android.widget.Toast
28+
import androidx.annotation.RequiresApi
29+
import androidx.constraintlayout.widget.ConstraintSet
30+
import androidx.fragment.app.Fragment
31+
import com.bumptech.glide.Glide
32+
import com.example.platform.ui.draganddrop.databinding.FragmentDragAndDropWithViewsBinding
33+
import com.google.android.catalog.framework.annotations.Sample
34+
35+
@Sample(
36+
name = "Drag and Drop using views",
37+
description = "Drag and Drop using the views",
38+
documentation = "https://developer.android.com/develop/ui/views/touch-and-input/drag-drop/view",
39+
)
40+
class DragAndDropWithViews : Fragment(R.layout.fragment_drag_and_drop_with_views) {
41+
42+
val TAG = "DragAndDropWithViews"
43+
private lateinit var binding: FragmentDragAndDropWithViewsBinding
44+
45+
@RequiresApi(Build.VERSION_CODES.N)
46+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
47+
super.onViewCreated(view, savedInstanceState)
48+
binding = FragmentDragAndDropWithViewsBinding.bind(view)
49+
ConstraintSet().clone(binding.root)
50+
51+
binding.tvGreeting.text = getString(R.string.view_greeting)
52+
binding.ivSource.tag = getString(R.string.views_source_image_url)
53+
Glide.with(this).asBitmap().load(getString(R.string.views_source_image_url))
54+
.into(binding.ivSource)
55+
Glide.with(this).asBitmap().load(getString(R.string.views_target_image_url))
56+
.into(binding.ivTarget)
57+
setupDrag(binding.ivSource)
58+
setupDrop(binding.ivTarget)
59+
// resetting the to state before drag
60+
binding.btnReset.setOnClickListener {
61+
Glide.with(this).asBitmap().load(getString(R.string.views_target_image_url))
62+
.into(binding.ivTarget)
63+
}
64+
}
65+
66+
@RequiresApi(Build.VERSION_CODES.N)
67+
private fun setupDrag(draggableView: ImageView) {
68+
draggableView.setOnLongClickListener { v ->
69+
val label = "Dragged Image Url"
70+
val clipItem = ClipData.Item(v.tag as? CharSequence)
71+
val mimeTypes = arrayOf(ClipDescription.MIMETYPE_TEXT_PLAIN)
72+
val draggedData = ClipData(
73+
label, mimeTypes, clipItem
74+
)
75+
v.startDragAndDrop(
76+
draggedData,
77+
View.DragShadowBuilder(v),
78+
null,
79+
View.DRAG_FLAG_GLOBAL or View.DRAG_FLAG_GLOBAL_URI_READ
80+
)
81+
}
82+
}
83+
84+
@RequiresApi(Build.VERSION_CODES.N)
85+
private fun setupDrop(dropTarget: ImageView) {
86+
dropTarget.setOnDragListener { v, event ->
87+
when (event.action) {
88+
DragEvent.ACTION_DRAG_STARTED -> {
89+
Log.d(TAG, "ON DRAG STARTED")
90+
if (event.clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) {
91+
(v as? ImageView)?.alpha = 0.5F
92+
v.invalidate()
93+
true
94+
} else {
95+
false
96+
}
97+
}
98+
99+
DragEvent.ACTION_DRAG_ENTERED -> {
100+
Log.d(TAG, "ON DRAG ENTERED")
101+
(v as? ImageView)?.alpha = 0.3F
102+
v.invalidate()
103+
true
104+
}
105+
106+
DragEvent.ACTION_DRAG_LOCATION -> {
107+
Log.d(TAG, "On DRAG LOCATION")
108+
true
109+
}
110+
111+
DragEvent.ACTION_DRAG_ENDED -> {
112+
Log.d(TAG, "ON DRAG ENDED")
113+
(v as? ImageView)?.alpha = 1.0F
114+
true
115+
}
116+
117+
DragEvent.ACTION_DRAG_EXITED -> {
118+
Log.d(TAG, "ON DRAG EXISITED")
119+
(v as? ImageView)?.alpha = 0.5F
120+
v.invalidate()
121+
true
122+
}
123+
124+
DragEvent.ACTION_DROP -> {
125+
Log.d(TAG, "On DROP")
126+
val dropPermission = requireActivity().requestDragAndDropPermissions(event)
127+
val item: ClipData.Item = event.clipData.getItemAt(0)
128+
val dragData = item.text
129+
Toast.makeText(requireContext(), "Dragged Data ${dragData}", Toast.LENGTH_SHORT).show()
130+
Glide.with(this).load(item.text).into(v as ImageView)
131+
(v as? ImageView)?.alpha = 1.0F
132+
dropPermission.release()
133+
true
134+
}
135+
136+
else -> {
137+
false
138+
}
139+
}
140+
}
141+
}
142+
}

samples/user-interface/draganddrop/src/main/res/layout/fragment_dnd_richcontent.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,11 @@
8181
android:layout_width="wrap_content"
8282
android:layout_height="wrap_content"
8383
android:hint="@string/editable_drag_text"
84+
android:inputType="text"
8485
app:layout_constraintBottom_toBottomOf="parent"
8586
app:layout_constraintLeft_toRightOf="@id/iv_source_1"
8687
app:layout_constraintRight_toRightOf="parent"
87-
app:layout_constraintTop_toBottomOf="@id/tv_drag"
88-
android:inputType="text"/>
88+
app:layout_constraintTop_toBottomOf="@id/tv_drag" />
8989

9090
<TextView
9191
android:id="@+id/tv_drag"
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?xml version="1.0" encoding="utf-8"?><!--
2+
~ Copyright 2023 The Android Open Source Project
3+
~
4+
~ Licensed under the Apache License, Version 2.0 (the "License");
5+
~ you may not use this file except in compliance with the License.
6+
~ You may obtain a copy of the License at
7+
~
8+
~ https://www.apache.org/licenses/LICENSE-2.0
9+
~
10+
~ Unless required by applicable law or agreed to in writing, software
11+
~ distributed under the License is distributed on an "AS IS" BASIS,
12+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
~ See the License for the specific language governing permissions and
14+
~ limitations under the License.
15+
-->
16+
17+
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
18+
xmlns:app="http://schemas.android.com/apk/res-auto"
19+
android:layout_width="match_parent"
20+
android:layout_height="match_parent">
21+
22+
<TextView
23+
android:id="@+id/tv_greeting"
24+
android:layout_width="wrap_content"
25+
android:layout_height="wrap_content"
26+
app:layout_constraintBottom_toTopOf="@id/btn_reset"
27+
app:layout_constraintLeft_toLeftOf="parent"
28+
app:layout_constraintRight_toRightOf="parent"
29+
app:layout_constraintTop_toTopOf="parent" />
30+
31+
<Button
32+
android:id="@+id/btn_reset"
33+
android:layout_width="wrap_content"
34+
android:layout_height="wrap_content"
35+
android:text="@string/reset_btn_text"
36+
app:layout_constraintBottom_toTopOf="@id/iv_source"
37+
app:layout_constraintLeft_toLeftOf="parent"
38+
app:layout_constraintRight_toRightOf="parent"
39+
app:layout_constraintTop_toBottomOf="@id/tv_greeting" />
40+
41+
<ImageView
42+
android:id="@+id/iv_source"
43+
android:layout_width="match_parent"
44+
android:layout_height="wrap_content"
45+
android:contentDescription="@string/source_image"
46+
app:layout_constraintBottom_toTopOf="@id/iv_target"
47+
app:layout_constraintLeft_toLeftOf="parent"
48+
app:layout_constraintRight_toRightOf="parent"
49+
app:layout_constraintTop_toBottomOf="@id/btn_reset" />
50+
51+
<ImageView
52+
android:id="@+id/iv_target"
53+
android:layout_width="match_parent"
54+
android:layout_height="wrap_content"
55+
android:contentDescription="@string/target_image"
56+
app:layout_constraintBottom_toBottomOf="parent"
57+
app:layout_constraintLeft_toLeftOf="parent"
58+
app:layout_constraintRight_toRightOf="parent"
59+
app:layout_constraintTop_toBottomOf="@id/iv_source" />
60+
61+
62+
</androidx.constraintlayout.widget.ConstraintLayout>

0 commit comments

Comments
 (0)