Let’s assume you are creating some cool notes app and you want to give users the ability to drag and drop the individual notes item and save their final positions let’s say in a database. Well the first step in that is understanding how to drag drop items in an adapterview, e.g listview, gridview, recyclerview.
In this article you will learn:
- How to drag and drop items in a grid.
- How to get the items final position.
We use the following languages:
- Kotlin
- Java
NB/= This article is broken down into several pages. Each page teaches a unique concept. Here are the taught concepts:
- Drag Drop in a Grid
- Drag Drop in a RecyclerView
Concept 1: Drag Drop in Grid
Example 1: Drap Drop Items in a GridView
Let us see how to drag drop items in a GridView.
Step 1: Dependencies
We use no third party dependencies.
Step 2: Code
We write our code in Java.
We have two classes, a fragment hosted inside an activity:
MainFragment.java
package info.camposha.dragdropexample;
/**
* ANDROID: http://www.camposha.info : Oclemy.
*/
import android.content.ClipData;
import android.graphics.Color;
import android.os.Bundle;
import android.view.DragEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import androidx.fragment.app.Fragment;
public class MainFragment extends Fragment {
private View[] views;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_main, container, false);
views = new View[rootView.getChildCount()];
for (int i = 0; i < rootView.getChildCount(); i++) {
final TextView view = (TextView) rootView.getChildAt(i);
initView(view);
views[i] = view;
}
return rootView;
}
private void initView(final TextView view) {
view.setOnDragListener((v, event) -> {
switch(event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
return true;
case DragEvent.ACTION_DRAG_ENTERED:
v.setBackgroundColor(Color.LTGRAY);
return true;
case DragEvent.ACTION_DRAG_LOCATION:
return true;
case DragEvent.ACTION_DRAG_EXITED:
v.setBackgroundColor(Color.TRANSPARENT);
return true;
case DragEvent.ACTION_DROP:
v.setBackgroundColor(Color.TRANSPARENT);
int dragVal = Integer.parseInt(event.getClipData().getItemAt(0).getText().toString());
int viewVal = Integer.parseInt(((TextView) v).getText().toString());
((TextView) v).setText("" + (dragVal + viewVal));
Toast.makeText(getContext(), "Added", Toast.LENGTH_SHORT).show();
return true;
case DragEvent.ACTION_DRAG_ENDED:
return true;
default:
break;
}
return false;
});
view.setOnLongClickListener(v -> {
ClipData data = ClipData.newPlainText("value", view.getText());
view.startDrag(data, new View.DragShadowBuilder(v), null, 0);
return true;
});
}
}
MainActivity
To host our fragment:
package info.camposha.dragdropexample;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
Step 3: Layouts
Copy the layout from the source code.
Step 4: Run
If your run the project you’ll get the following:
Step 5: Download
Download the full source code here.
Example 2: Kotlin Android Drag Drop
This is a simple example showing howto implement drag and drop in Kotlin.
Step 1: Create Project
Start by creating an empty Android Studio
project.
Step 2: Dependencies
No third party library is needed for our implementation of Drag Drop.
Step 3: Create a Drag and Drop Container
You need to create a custom Drag and drop layout. This layout is based on the FrameLayout and will be used in our layout:
DragAndDropContainer.kt
package supahsoftware.androidexampledragdrop
import android.content.ClipData
import android.content.ClipDescription
import android.content.Context
import android.os.Build
import android.util.AttributeSet
import android.view.View
import android.widget.FrameLayout
class DragAndDropContainer(
context: Context,
attrs: AttributeSet?
) : FrameLayout(context, attrs) {
private val dragAndDropListener by lazy { DragAndDropListener() }
private var content: View? = null
init {
setOnDragListener(dragAndDropListener)
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
updateChild()
}
fun setContent(view: View) {
removeAllViews()
addView(view)
updateChild()
}
fun removeContent(view: View) {
view.setOnLongClickListener(null)
removeView(view)
updateChild()
}
private fun updateChild() {
validateChildCount()
content = getFirstChild()
content?.setOnLongClickListener { startDrag() }
}
private fun getFirstChild() = if (childCount == 1) getChildAt(0) else null
private fun validateChildCount() = check(childCount <= 1) {
"There should be a maximum of 1 child inside of a DragAndDropContainer, but there were $childCount"
}
private fun startDrag(): Boolean {
content?.let {
val tag = it.tag as? CharSequence
val item = ClipData.Item(tag)
val data = ClipData(tag, arrayOf(ClipDescription.MIMETYPE_TEXT_PLAIN), item)
val shadow = DragShadowBuilder(it)
if (Build.VERSION.SDK_INT >= 24) {
it.startDragAndDrop(data, shadow, it, 0)
} else {
it.startDrag(data, shadow, it, 0)
}
return true
} ?: return false
}
}
Step 4: Design Layout
Design your MainActivity’s layout as follows:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<supahsoftware.androidexampledragdrop.DragAndDropContainer
android:id="@+id/container_1"
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:background="@drawable/outline_gray_solid"
app:layout_constraintTop_toTopOf="parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/content_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/banner"
android:scaleType="center" />
</FrameLayout>
</supahsoftware.androidexampledragdrop.DragAndDropContainer>
<supahsoftware.androidexampledragdrop.DragAndDropContainer
android:id="@+id/container_2"
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:background="@drawable/outline_gray_solid"
app:layout_constraintTop_toBottomOf="@id/container_1" />
<supahsoftware.androidexampledragdrop.DragAndDropContainer
android:id="@+id/container_3"
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:background="@drawable/outline_gray_solid"
app:layout_constraintTop_toBottomOf="@id/container_2" />
<supahsoftware.androidexampledragdrop.DragAndDropContainer
android:id="@+id/container_4"
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:background="@drawable/outline_gray_solid"
app:layout_constraintTop_toBottomOf="@id/container_3" />
</androidx.constraintlayout.widget.ConstraintLayout>
Step 5: Create a Drag and Drop Listener
As follows:
DragAndDropListener.kt
package supahsoftware.androidexampledragdrop
import android.content.ClipDescription
import android.view.DragEvent
import android.view.View
import androidx.core.content.ContextCompat
class DragAndDropListener : View.OnDragListener {
override fun onDrag(view: View, event: DragEvent): Boolean {
return when (event.action) {
DragEvent.ACTION_DRAG_ENTERED -> {
view.setDashedOutline(); true
}
DragEvent.ACTION_DRAG_EXITED -> {
view.setSolidOutline(); true
}
DragEvent.ACTION_DROP -> {
val draggingView = event.localState as View
val draggingViewParent = draggingView.parent as DragAndDropContainer
draggingViewParent.removeContent(draggingView)
val landingContainer = view as DragAndDropContainer
landingContainer.setContent(draggingView)
landingContainer.setSolidOutline()
true
}
DragEvent.ACTION_DRAG_STARTED -> event.clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)
else -> true
}
}
private fun View.setSolidOutline() {
background = ContextCompat.getDrawable(context, R.drawable.outline_gray_solid)
}
private fun View.setDashedOutline() {
background = ContextCompat.getDrawable(context, R.drawable.outline_gray_dashed)
}
}
Step 6: Create MainActivity
Create MainActivity as follows:
MainActivity.kt
package supahsoftware.androidexampledragdrop
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
Run
Copy the code or download it in the link below, build and run.
Reference
Here are the reference links:
Number | Link |
---|---|
1. | Download Example |
2. | Follow code author |
3. | Code: Apache 2.0 License |
Concept 2: Drag and Drop in RecyclerView