[go: nahoru, domu]

Skip to content

Commit

Permalink
Drag and Drop using views
Browse files Browse the repository at this point in the history
Change-Id: I78a68213910b38c3818ff8cf5519a37da8ebd6eb
  • Loading branch information
satishshendeg committed May 15, 2024
1 parent ce4c345 commit 307b67b
Show file tree
Hide file tree
Showing 11 changed files with 263 additions and 38 deletions.
2 changes: 2 additions & 0 deletions samples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ Drag and drop in Compose
Drag and drop to another app visible in multiwindow mode
- [Drag and Drop using the RichContentReceiver](user-interface/draganddrop/src/main/java/com/example/platform/ui/draganddrop/DragAndDropRichContentReceiverFragment.kt):
Using RichContentReceiverInterface for implementing Drop for rich data types
- [Drag and Drop using views](user-interface/draganddrop/src/main/java/com/example/platform/ui/draganddrop/DragAndDropWithViews.kt):
Drag and Drop using the views
- [Editing UltraHDR](graphics/ultrahdr/src/main/java/com/example/platform/graphics/ultrahdr/edit/EditingUltraHDR.kt):
This sample demonstrates editing an UltraHDR image and the resulting gainmap as well. Spatial edit operations like crop, rotate, scale are supported
- [Find devices sample](connectivity/bluetooth/ble/src/main/java/com/example/platform/connectivity/bluetooth/ble/FindBLEDevicesSample.kt):
Expand Down
34 changes: 21 additions & 13 deletions samples/user-interface/draganddrop/README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
# Drag and Drop

An android application demonstrating basic Drag and Drop functionality using the
[`Jetpack Drag and Drop Library`](https://developer.android.com/jetpack/androidx/releases/draganddrop).

Allows for plain-text items and images to be dragged into the app. Has a plain-text item and a PNG
item that can be dragged within, out of, or to a second instance of the demo.

Utilizes [`androidx.core`](https://developer.android.com/jetpack/androidx/releases/core)'s
[`DragStartHelper`](https://developer.android.com/reference/kotlin/androidx/core/view/DragStartHelper)
and [`androidx.draganddrop`](https://developer.android.com/jetpack/androidx/releases/draganddrop)'s
[`DropHelper`](https://developer.android.com/reference/kotlin/androidx/draganddrop/DropHelper) to
simplify the process of implementing both dragging and dropping functionality.
# Drag and Drop Samples

The samples in this directory address various various ways of implementing Drag and Drop, along with
implementation of RichContentReceiver

- [Drag and Drop using Views](src/main/java/com/example/platform/ui/draganddrop/DragAndDropWithViews.kt)
This sample demonstrate basic implementation with onLongClickListener and implementing
DragListener callback
- [Drag and Drop in Multi-Window mode](src/main/java/com/example/platform/ui/draganddrop/DragAndDropMultiWindow.kt)
This sample demonstrate the drag-and-drop across apps.
- [Drag and Drop using DragAndDropHelper Library](src/main/java/com/example/platform/ui/draganddrop/DragAndDropWithHelper.kt)
This sample uses
the [`Jetpack Drag and Drop Library`](https://developer.android.com/jetpack/androidx/releases/draganddrop)
to demonstrate drag-and-drop.
- [Drag and Drop in compose](src/main/java/com/example/platform/ui/draganddrop/DragAndDropUsingCompose.kt)
This sample showcase drag-and-drop implementation in compose.
- [Accepting rich media](src/main/java/com/example/platform/ui/draganddrop/DragAndDropRichContentReceiverFragment.kt)
This sample showcase how rich media can be handled using RichContentReceiver unified Api which
works for drag-and-drop, keyboard and clipboard

> **Important:** All samples run independent of each other.
## License

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import androidx.core.util.component2
import androidx.core.view.DragStartHelper
import androidx.draganddrop.DropHelper
import com.example.platform.ui.draganddrop.databinding.DragAndDropActivityBinding
import com.google.android.catalog.framework.annotations.Sample
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileInputStream
Expand All @@ -51,11 +50,13 @@ private const val TAG = "DragDropSample"
private const val MAX_LENGTH = 200

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

private lateinit var binding: DragAndDropActivityBinding
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ package com.example.platform.ui.draganddrop

import androidx.core.content.FileProvider

@Deprecated("Along with DragAndDropActivity")
class DragAndDropFileProvider: FileProvider()
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import com.google.android.catalog.framework.annotations.Sample
@Sample(
name = "Drag and Drop in MultiWindow mode",
description = "Drag and drop to another app visible in multiwindow mode",
documentation = "",
documentation = "https://developer.android.com/develop/ui/views/touch-and-input/drag-drop/multi-window",
)
class DragAndDropMultiWindow : Fragment(R.layout.fragment_dnd_multiwindow) {
lateinit var binding: FragmentDndMultiwindowBinding
Expand All @@ -47,11 +47,11 @@ class DragAndDropMultiWindow : Fragment(R.layout.fragment_dnd_multiwindow) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentDndMultiwindowBinding.bind(view)
ConstraintSet().clone(binding.root)
binding.tvGreeting.text = resources.getString(R.string.dnd_multiwindow_greeting)
binding.ivSource.tag = resources.getString(R.string.source_image_url)
Glide.with(this).asBitmap().load(resources.getString(R.string.source_image_url))
binding.tvGreeting.text = resources.getString(R.string.multiwindow_greeting)
binding.ivSource.tag = resources.getString(R.string.multi_source_image_url)
Glide.with(this).asBitmap().load(resources.getString(R.string.multi_source_image_url))
.into(binding.ivSource)
Glide.with(this).asBitmap().load(resources.getString(R.string.target_image_url))
Glide.with(this).asBitmap().load(resources.getString(R.string.multi_target_image_url))
.into(binding.ivTarget)
setupDrag(binding.ivSource)
setupDrop(binding.ivTarget)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class DragAndDropRichContentReceiverFragment : Fragment(R.layout.fragment_dnd_ri
binding = FragmentDndRichcontentBinding.bind(view)
ConstraintSet().clone(binding.root)
val items = mutableListOf<GridItem>()
// binding.tvGreeting.text = getString(R.string.rich_content_greeting)
initViews(items)
initDrag()

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

@RequiresApi(Build.VERSION_CODES.N)
fun initDrag() {
Glide.with(this).asBitmap().load(getString(R.string.target_image_url))
Glide.with(this).asBitmap().load(getString(R.string.rich_source_image_url))
.into(binding.ivSource1)
addDragStartHelperForImageView(binding.ivSource1)
Glide.with(this).asBitmap().load(getString(R.string.target_image_url1))
Glide.with(this).asBitmap().load(getString(R.string.rich_target_image_url))
.into(binding.ivSource)
addDragStartHelperForImageView(binding.ivSource)

binding.tvDrag.text = getString(R.string.dnd_helper_greeting)
binding.tvDrag.text = getString(R.string.rich_content_greeting)
addDragStartHelperForTextView(binding.tvDrag)

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,23 +49,23 @@ class DragAndDropWithHelper : Fragment(R.layout.fragment_drag_and_drop_with_help
binding = FragmentDragAndDropWithHelperBinding.bind(view)
ConstraintSet().clone(binding.root)

binding.tvGreeting.text = getString(R.string.dnd_helper_greeting)
binding.tvGreeting.text = getString(R.string.helper_greeting)
/*
data for drag
for simplicity we have considered text as a data type to drag
For rich content like Image to be used as drag data type please check the sample for
Drag and Drop - rich content
*/
binding.ivSource.tag = getString(R.string.source_image_url)
Glide.with(this).asBitmap().load(getString(R.string.source_image_url))
binding.ivSource.tag = getString(R.string.helper_source_image_url)
Glide.with(this).asBitmap().load(getString(R.string.helper_source_image_url))
.into(binding.ivSource)
Glide.with(this).asBitmap().load(getString(R.string.target_image_url))
Glide.with(this).asBitmap().load(getString(R.string.helper_target_image_url))
.into(binding.ivTarget)
setupDrag(binding.ivSource)
setupDrop(binding.ivTarget)
// resetting the to state before drag
binding.btnReset.setOnClickListener {
Glide.with(this).asBitmap().load(getString(R.string.target_image_url))
Glide.with(this).asBitmap().load(getString(R.string.helper_target_image_url))
.into(binding.ivTarget)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
* Copyright 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.example.platform.ui.draganddrop

import android.content.ClipData
import android.content.ClipDescription
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.DragEvent
import android.view.View
import android.widget.ImageView
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.constraintlayout.widget.ConstraintSet
import androidx.fragment.app.Fragment
import com.bumptech.glide.Glide
import com.example.platform.ui.draganddrop.databinding.FragmentDragAndDropWithViewsBinding
import com.google.android.catalog.framework.annotations.Sample

@Sample(
name = "Drag and Drop using views",
description = "Drag and Drop using the views",
documentation = "https://developer.android.com/develop/ui/views/touch-and-input/drag-drop/view",
)
class DragAndDropWithViews : Fragment(R.layout.fragment_drag_and_drop_with_views) {

val TAG = "DragAndDropWithViews"
private lateinit var binding: FragmentDragAndDropWithViewsBinding

@RequiresApi(Build.VERSION_CODES.N)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentDragAndDropWithViewsBinding.bind(view)
ConstraintSet().clone(binding.root)

binding.tvGreeting.text = getString(R.string.view_greeting)
binding.ivSource.tag = getString(R.string.views_source_image_url)
Glide.with(this).asBitmap().load(getString(R.string.views_source_image_url))
.into(binding.ivSource)
Glide.with(this).asBitmap().load(getString(R.string.views_target_image_url))
.into(binding.ivTarget)
setupDrag(binding.ivSource)
setupDrop(binding.ivTarget)
// resetting the to state before drag
binding.btnReset.setOnClickListener {
Glide.with(this).asBitmap().load(getString(R.string.views_target_image_url))
.into(binding.ivTarget)
}
}

@RequiresApi(Build.VERSION_CODES.N)
private fun setupDrag(draggableView: ImageView) {
draggableView.setOnLongClickListener { v ->
val label = "Dragged Image Url"
val clipItem = ClipData.Item(v.tag as? CharSequence)
val mimeTypes = arrayOf(ClipDescription.MIMETYPE_TEXT_PLAIN)
val draggedData = ClipData(
label, mimeTypes, clipItem
)
v.startDragAndDrop(
draggedData,
View.DragShadowBuilder(v),
null,
View.DRAG_FLAG_GLOBAL or View.DRAG_FLAG_GLOBAL_URI_READ
)
}
}

@RequiresApi(Build.VERSION_CODES.N)
private fun setupDrop(dropTarget: ImageView) {
dropTarget.setOnDragListener { v, event ->
when (event.action) {
DragEvent.ACTION_DRAG_STARTED -> {
Log.d(TAG, "ON DRAG STARTED")
if (event.clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) {
(v as? ImageView)?.alpha = 0.5F
v.invalidate()
true
} else {
false
}
}

DragEvent.ACTION_DRAG_ENTERED -> {
Log.d(TAG, "ON DRAG ENTERED")
(v as? ImageView)?.alpha = 0.3F
v.invalidate()
true
}

DragEvent.ACTION_DRAG_LOCATION -> {
Log.d(TAG, "On DRAG LOCATION")
true
}

DragEvent.ACTION_DRAG_ENDED -> {
Log.d(TAG, "ON DRAG ENDED")
(v as? ImageView)?.alpha = 1.0F
true
}

DragEvent.ACTION_DRAG_EXITED -> {
Log.d(TAG, "ON DRAG EXISITED")
(v as? ImageView)?.alpha = 0.5F
v.invalidate()
true
}

DragEvent.ACTION_DROP -> {
Log.d(TAG, "On DROP")
val dropPermission = requireActivity().requestDragAndDropPermissions(event)
val item: ClipData.Item = event.clipData.getItemAt(0)
val dragData = item.text
Toast.makeText(requireContext(), "Dragged Data ${dragData}", Toast.LENGTH_SHORT).show()
Glide.with(this).load(item.text).into(v as ImageView)
(v as? ImageView)?.alpha = 1.0F
dropPermission.release()
true
}

else -> {
false
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,11 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="@string/editable_drag_text"
android:inputType="text"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@id/iv_source_1"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_drag"
android:inputType="text"/>
app:layout_constraintTop_toBottomOf="@id/tv_drag" />

<TextView
android:id="@+id/tv_drag"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ https://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
android:id="@+id/tv_greeting"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@id/btn_reset"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<Button
android:id="@+id/btn_reset"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/reset_btn_text"
app:layout_constraintBottom_toTopOf="@id/iv_source"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_greeting" />

<ImageView
android:id="@+id/iv_source"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="@string/source_image"
app:layout_constraintBottom_toTopOf="@id/iv_target"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_reset" />

<ImageView
android:id="@+id/iv_target"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="@string/target_image"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/iv_source" />


</androidx.constraintlayout.widget.ConstraintLayout>
Loading

0 comments on commit 307b67b

Please sign in to comment.