banner



How To Stop A Click From Being Registered From A Drag Android

Prepare to delight your users with the Android drag-and-drop framework?

Drag and drop seems like magic considering it gives your app users the adequacy to move UI elements by performing gestures on the screen. In this tutorial, you'll learn about the events and deportment that drive this framework so you tin become a drag-and-drop wizard! You'll create an app named Masky that lets you drag a mask onto the screen and drop information technology over an unmasked confront. More specifically, you lot'll larn how to:

  1. Design drag-and-drop operations.
  2. Customize the elevate shadow.
  3. Reply to drag-and-drop events.
  4. Move a view — the mask — across the screen to its new drop area.
  5. Check if the mask view is on the face up.

Note: This tutorial assumes yous have a bones working knowledge of the Kotlin programming language and Android evolution. If you demand to brush up on your skills, check out our Android and Kotlin for Beginners learning path or our books, Android Amateur and Kotlin Amateur.

Yous'll start by looking at the starter project and learning how elevate and drop works.

Getting Started

Download the starter project by clicking the Download Materials button at the top or lesser of the tutorial.

Open up the starter project in Android Studio. Build and run. You'll see the following screen:

Masky Drag and Drop Starter Project

The app currently shows the mask and the unmasked face, simply you tin't do annihilation with them yet. The starter project is a clean slate, set up for you to start working on information technology. Equally you follow along with the tutorial, you lot'll see the app take shape.

The Elevate-and-Drop Procedure

Android's drag-and-drop framework lets users move information and views using graphical gestures. Users tin drag and driblet data across views inside the same app or even from ane app to another, if they have multi-window mode enabled.

In this tutorial, yous'll utilize framework internals like elevate event classes and drag listeners to design your own drag-and-driblet operations.

The Four Elevate-and-Drop States

The drag-and-drib process consists of four states:

  1. Started
  2. Continuing
  3. Dropped
  4. Ended

Now, yous'll take a await at each of these states, as the diagram below illustrates.

Android-Drag-Drop-States
Started State

When the user makes a UI gesture that your app recognizes every bit a trigger, such as a long click, the elevate procedure begins. The app provides drag data along with a drag shadow callback every bit arguments to the system via startDragAndDrop().

Note: To kickoff a drag, utilize startDragAndDrop() for Nougat devices and newer. For pre-Nougat devices apply startDrag().

The system first displays a drag shadow, which can be either a shadow or an bodily draggable view, on the device. It uses the action type ACTION_DRAG_STARTED to acceleration a drag event to all the registered drag event listeners in the current layout.

The elevate event listener returns a Boolean truthful to go along receiving elevate events. If the listener just needs to know when the elevate has ended, information technology can opt out of receiving the drag data past returning false instead. This ensures that the listener volition only receive the final elevate event with the activeness blazon ACTION_DRAG_ENDED.

Annotation: The following DragEvent methods are not valid on the ACTION_DRAG_STARTED upshot action blazon:

  • getClipData()
  • getX()
  • getY()
  • getResult()

Continuing State

Equally the user continues to drag, the elevate procedure enters the continuing country.

In this country, the organization dispatches one or more drag events to registered elevate event listeners.

For example, every bit the drag shadow enters the bounding box of the view that is registered for elevate events, the organisation dispatches the action blazon ACTION_DRAG_ENTERED to the listener.

After receiving an ACTION_DRAG_ENTERED event and earlier it tin can receive an ACTION_DRAG_EXITED event, the listener receives a new ACTION_DRAG_LOCATION event every bit the drag continues. Hither yous can retrieve the electric current 10, y coordinates of the draggable view.

As well, when the elevate shadow leaves the bounding box, an ACTION_DRAG_EXITED action blazon is sent to the listener.

In your app, you lot'll just bargain with the ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED action types.

Dropped Country

When the user releases the drag shadow over a view that'south registered for drag events, the system dispatches a drag event with action type ACTION_DROP.

Y'all think data passed from this elevate result as arguments in startDragAndDrop()/startDrag().

Ended State

Finally, the system wraps upward the drag operation by dispatching a drag event with the activity blazon ACTION_DRAG_ENDED.

Afterwards receiving ACTION_DRAG_ENDED, each drag issue listener should:

  1. Reset all the state or UI changes you made during the drag operation.
  2. Render a Boolean true.
  3. Optionally, check the drop success status by invoking getResult().

At present that you have a theoretical understanding of Android elevate-and-drop operations, it's fourth dimension to use this cognition in a real app!

Designing a Drag Operation

At present, it'southward fourth dimension to implement drag and drop in Masky. You'll program the app to let the user drag the mask around the screen and drib it over an unmasked confront. After the user drops the mask, a toast message will notify them virtually whether the mask is on or off the face up.

For this app, yous'll apply a long click to start the drag operation.

Calculation a Drag Shadow

The system displays a placeholder image to represent the actual view/information during a drag operation. This placeholder image representation is the drag shadow.

drag shadow android

To create a drag shadow builder, you bracket View.DragShadowBuilder. Y'all can and so pass the builder as an statement to the organisation when yous commencement a drag performance using startDragAndDrop() or startDrag().

The system then uses the elevate shadow builder to invoke its callback methods to obtain a elevate shadow.

If you don't want to brandish a drag shadow, you don't have to. You command whether the drib shadow displays or not past picking the advisable View.DragShadowBuilder constructor:

  1. View.DragShadowBuilder(view): Accepts a View object to create a drag shadow that looks like to the view object the user is dragging. To customize your drag shadow, yous can subclass this class and override the methods, every bit you'll see later.
  2. View.DragShadowBuilder(): This drag shadow architect has no parameters and volition give you an invisible drag shadow. As the user drags the view, there's no visual cue that the drag is in progress until information technology ends.

Your next step is to customize the drag shadow to match your requirements past subclassing View.DragShadowBuilder(view).

Customizing a Elevate Shadow

When you use the default constructor, View.DragShadowBuilder(view), you lot'll get a default drag shadow. The default values in a drag shadow have the same dimensions as the argument View.

The bear upon signal is the location of the user'due south finger within the drag shadow. The default bear on point is at the middle of the argument View.

Before you lot can kickoff customizing your drag shadow, you need to import the following packages:

import android.graphics.Canvas import android.graphics.Point import android.view.View import androidx.core.content.res.ResourcesCompat        

Next, add MaskDragShadowBuilder by adding the following code to MainActivity.kt:

private class MaskDragShadowBuilder(view: View) : View.DragShadowBuilder(view) {    //1   individual val shadow = ResourcesCompat.getDrawable(view.context.resource, R.drawable.ic_mask, view.context.theme)    // two   override fun onProvideShadowMetrics(size: Point, affect: Indicate) {     // 3     val width: Int = view.width      // 4     val elevation: Int = view.height      // 5     shadow?.setBounds(0, 0, width, height)      // vi     size.set(width, height)      // 7     touch on.ready(width / 2, height / 2)   }    // 8   override fun onDrawShadow(canvas: Canvas) {     // nine     shadow?.draw(canvas)   } }        

This code creates a drag shadow that looks like the mask the user volition elevate. Here's how it works:

  1. Sets the drag shadow appearance to match the actual mask. The drag shadow hither is of a Drawable type.
  2. Invokes onProvideShadowMetrics() when you trigger startDragAndDrop() or startDrag().
  3. Defines the width of the elevate shadow to be the full width of the mask View.
  4. Defines the peak of the elevate shadow to be the full height of the mask View.
  5. Sets the dimensions and kickoff position of the drag shadow on the sheet.
  6. Adjusts the size parameter's width and acme values.
  7. Sets the drag shadow touch point position to the middle of the elevate shadow.
  8. Calls onDrawShadow() after calling onProvideShadowMetrics(). onDrawShadow() draws the actual drag shadow on a canvas object using the metrics from onProvideShadowMetrics().
  9. Draws the mask's drag shadow Drawable in the Canvas.

Now that you have a drag shadow, information technology's time to accept care of the drag event listeners.

Implementing a Drag Result Listener

When the drag-and-drop process is in progress, the organisation sends a DragEvent to all the registered elevate result listeners.

Next, you'll implement View.OnDragListener to create a drag event listener object, and so set the listener on the View'southward setOnDragListener().

Dispatching Drag Events

The organisation uses DragEvent to acceleration a elevate event along with its associated data and activeness type. The action blazon in the DragEvent updates the registered listeners on what'southward happening in the drag-and-drop procedure.

DragEvent defines half dozen activity blazon constants:

  1. ACTION_DRAG_STARTED
  2. ACTION_DRAG_ENTERED
  3. ACTION_DRAG_LOCATION
  4. ACTION_DRAG_EXITED
  5. ACTION_DROP
  6. ACTION_DRAG_ENDED

You tin can read the summary of each action type in the official Android documentation.

To access the action type constants, invoke getAction() on DragEvent.

DragEvent also contains optional data items valid for a specific activity type. Read more nearly them in the official Android documentation.

Starting a Elevate Operation

Earlier starting a drag operation, familiarize yourself with activity_main.xml. This file contains the main layout for the drag-and-drib feature you'll implement.

Focus on the following views:

  • Mask view: The ImageView.
  • Unmasked face: The Bugdroid mascot ImageView.
  • Mask drop surface area: The ConstraintLayout, which is the complete area within the dashed line boundary that represents the bounding box for drag enter/get out events.

Open up MainActivity.kt and add attachViewDragListener() to information technology. attachViewDragListener() defines the set of deportment to perform to outset a drag operation.

Next, import the post-obit packages:

import android.content.ClipData import android.content.ClipDescription import android.os.Build import android.os.Bundle        

And then, call attachViewDragListener() in the onCreate() lifecycle callback of your activeness:

individual fun attachViewDragListener() {    // 1   binding.mask.setOnLongClickListener { view: View ->    // 2   val item = ClipData.Detail(maskDragMessage)    // iii   val dataToDrag = ClipData(       maskDragMessage,       arrayOf(ClipDescription.MIMETYPE_TEXT_PLAIN),       item   )    // 4   val maskShadow = MaskDragShadowBuilder(view)    // v   if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {      //back up pre-Nougat versions      @Suppress("DEPRECATION")      view.startDrag(dataToDrag, maskShadow, view, 0)   } else {      //supports Nougat and beyond      view.startDragAndDrop(dataToDrag, maskShadow, view, 0)   }    // half-dozen   view.visibility = View.INVISIBLE    //7   true  } }        

The code in a higher place adds drag first capabilities to the app. Hither's how:

  1. The current layout calls for you lot to elevate the mask view across other views. To exercise this, yous set a long-click listener on the mask view that triggers the elevate start.
  2. Create ClipData and ClipData.Item, which represent the data the user is dragging.
  3. Within ClipData, you include the array of MIME types the information represents, with the help of ClipDescription. If y'all don't want to support data movement, yous tin can simply pass a null value for the MIME types.
  4. Instantiate a drag shadow builder. Y'all don't need to customize the drag shadow, so yous employ
    the default View.DragShadowBuilder(view).
  5. Here, you supply ClipData, the elevate shadow builder and a mask view that yous want to elevate every bit arguments to startDrag().
  6. Hide the mask view when the drag starts. Only the drag shadow should be visible during a elevate operation.
  7. Return a Boolean true to tell the system that the click event was successful.

Build and run. At present, you can finally move the mask.

Android drag start operation

At this moment, however, your app but supports the elevate operation. When you release the mask, it disappears. To allow the user drop the mask, you'll add together lawmaking to answer to events side by side.

Responding to Drag Events

To respond to elevate events, you need to annals a drag event listener with the maskDropArea view. Only views that have elevate event listeners prepare can respond to drag events.

To first, open MainActivity.kt And add together the following:

// i private val maskDragListener = View.OnDragListener { view, dragEvent ->    //two   val draggableItem = dragEvent.localState every bit View    //three   when (dragEvent.action) {     DragEvent.ACTION_DRAG_STARTED -> {       true     }     DragEvent.ACTION_DRAG_ENTERED -> {       view.invalidate()       true     }     DragEvent.ACTION_DRAG_LOCATION -> {       true     }     DragEvent.ACTION_DRAG_EXITED -> {       true     }     DragEvent.ACTION_DROP -> {       true     }     DragEvent.ACTION_DRAG_ENDED -> {       truthful     }     else -> {       false     }   } }        

The lawmaking to a higher place creates a drag event listener. Here'due south how it works:

  1. Creates an instance of View.OnDragListener and assigns information technology to a variable, maskDragListener.
  2. Retrieves a reference to the mask view.
  3. A elevate event listener tin access getAction() to read the action blazon. Upon receiving the elevate event, you lot match the action blazon to perform appropriate tasks.

Notice that all the branches in the when expression render a Boolean true, except the else branch.

Next, add the following in onCreate():

bounden.maskDropArea.setOnDragListener(maskDragListener)        

You take a reference to the mask driblet area view that will answer to drag events. You then pass the elevate result listener, maskDragListener, into the view's setOnDragListener().

Handling Events During the Drag

Right now, there'south no visual indication to show where the user can or can't drop the mask. Your next step will be to handle events during the drag procedure to alter the drop area view depending on where the mask is.

Add the post-obit code snippets to your maskDragListener.

DragEvent.ACTION_DRAG_ENTERED -> {   binding.maskDropArea.alpha = 0.3f   true }        

The lawmaking in a higher place dims the drop area view when the mask enters the drop expanse premises. This indicates to the user that the mask is within the drop area.

DragEvent.ACTION_DRAG_EXITED -> {   binding.maskDropArea.alpha = 1.0f   draggableItem.visibility = View.VISIBLE   view.invalidate()   truthful }        

This code resets the drop area view opacity to 1.0f and resets the visibility of the mask view to VISIBLE when information technology exits the drib expanse premises. This visually indicates that dragging outside the bounds after dropping doesn't piece of work.

At present, y'all're ready to permit the user drop the mask.

Handling a Drop Operation

When the user releases the mask drag shadow, the organization needs to dispatch a elevate issue with the activeness type ACTION_DROP to the View with the listener. To implement this, add the following code snippet to your maskDragListener.

DragEvent.ACTION_DROP -> {   //1   binding.maskDropArea.alpha = 1.0f   //2   if (dragEvent.clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) {     val draggedData = dragEvent.clipData.getItemAt(0).text     //TODO : perform any action on the draggedData   }   //3   truthful }        

The code in a higher place performs the following actions on the elevate event listener:

  1. Resets the drib area view opacity to 1.0f when the user drops the mask.
  2. Optionally reads the data from ClipData via getClipData().
  3. Later the processing completes successfully, return a Boolean true or a Boolean false. ACTION_DRAG_ENDED volition render this value when you call getResult().

The user tin release the elevate shadow on whatever view, but the arrangement dispatches a drag event only if the drop surface area has an active drag issue listener indicating that it's set to accept the drop.

Responding to Drag Finish Events

When the user drops the drag shadow, the organization dispatches a elevate event to all the registered elevate event listeners with an activeness blazon of ACTION_DRAG_ENDED.

Receiving ACTION_DRAG_ENDED marks the terminate of the drag operation.

Setting the View Visibility

Right after dispatching ACTION_DROP, the system needs to dispatch ACTION_DRAG_ENDED. Add together the following lawmaking snippet to your maskDragListener to set the visibility of the mask view:

DragEvent.ACTION_DRAG_ENDED -> {   draggableItem.visibility = View.VISIBLE   view.invalidate()   truthful }        

When the drag starts, you set the visibility of the mask view to invisible. When the mask is in its new position, you demand to redraw the mask. That's what the code above does.

Next, you lot'll meet how to move the object to its new position when the user drops it.

Moving the Draggable View to a New Position

When the user drops the mask's draggable view onto the drib expanse, you need to position the mask in the drop location. That'due south your next goal.

Retrieving the Driblet'southward 10 and Y Position

You'll start by getting the Ten and Y position of the drag shadow release location from the drag event. This lets you position the mask in the drop area. To exercise this, call the following lawmaking from within the drag issue listener implementation for the ACTION_DROP event:

dragEvent.x dragEvent.y        

To think the ten, y coordinates from the elevate event object, use the getX() and getY() getter methods. The x, y coordinates from the drag event lucifer the last position of the mask drag shadow before the user dropped information technology.

Updating the Draggable View's Position

In Android, every view on the canvass starts calculating its position from the left-top corner and ends at the bottom-right corner.

If yous employ the x, y coordinates from the drag event to position the mask, it will anchor to the left-top corner coordinates.

Instead, yous want to anchor the center of the mask to the 10, y coordinates of the final bear on point location. To attain this, you need to make the following changes before updating the mask's new position.

Create a reference to the draggable mask view: val draggableItem = dragEvent.localState as View.

To update the draggable mask view's ten, y coordinates, first import androidx.constraintlayout.widget.ConstraintLayout. And then, add together the post-obit code snippet to your maskDragListener's DragEvent.ACTION_DROP co-operative:

//1 draggableItem.x = dragEvent.x - (draggableItem.width / 2) //2 draggableItem.y = dragEvent.y - (draggableItem.height / two)  //iii val parent = draggableItem.parent as ConstraintLayout //iv parent.removeView(draggableItem)  //v val dropArea = view as ConstraintLayout //6 dropArea.addView(draggableItem) //7 true        

This code aligns the center of the mask with the concluding bear upon bespeak before the drop. Information technology besides removes the mask from its previous location and adds it to the new location. Going through it pace by pace, you:

  1. Reposition the mask with the updated ten coordinate. Subtract half the width of the mask view from the elevate event'southward x coordinate. Then, assign the departure in value to the 10 coordinate of draggableItem.
  2. Reposition the mask with the updated y coordinate. Decrease half the tiptop of the mask view from the drag event'southward y coordinate. Assign the difference in value to the y coordinate of draggableItem.
  3. Take a reference to the mask's parent viewGroup.
  4. Remove the mask from the parent viewGroup.
  5. Take a reference to the new viewGroup, the mask drop area.
  6. Add the mask view to this new viewGroup.
  7. Return a Boolean true to indicate the drop operation succeeded.

At this point, the elevate-and-driblet operation works, simply you take one last improvement to make.

Indicating Whether the Mask Is on the Face up

To spice things upward, your next step is to let your app point whether the mask is on or off the confront.

Invoke a new method, checkIfMaskIsOnFace(dragEvent: DragEvent), in the maskDragListener's DragEvent.ACTION_DROP branch, just earlier returning true:

DragEvent.ACTION_DROP -> {   ...   checkIfMaskIsOnFace(dragEvent)   true }        

In checkIfMaskIsOnFace() you will create a reference to the face view, the Bugdroid mascot, to measure the bounds of the view. If the drag event'southward 10 and y coordinates are inside the bounds of the face view, and then the mask is on the confront.

Side by side, add the following variables in MainActivity.kt:

private val maskOn = "Bingo! Mask On" private val maskOff = "Mask off"        

These will serve as the text values for the toast message that checkIfMaskIsOnFace() will make.

Now it's time to create checkIfMaskIsOnFace(dragEvent: DragEvent). Start by importing android.widget.Toast.

Implement checkIfMaskIsOnFace(dragEvent: DragEvent) in MainActivity.kt to display the appropriate toast message:

private fun checkIfMaskIsOnFace(dragEvent: DragEvent) {   //1   val faceXStart = binding.faceArea.x   val faceYStart = binding.faceArea.y    //2   val faceXEnd = faceXStart + binding.faceArea.width   val faceYEnd = faceYStart + bounden.faceArea.height   //3   val toastMsg = if (dragEvent.ten in faceXStart..faceXEnd && dragEvent.y in faceYStart..faceYEnd){     maskOn   } else {     maskOff   }   //4   Toast.makeText(this, toastMsg, Toast.LENGTH_SHORT).prove() }        

Here's what the code to a higher place does:

  1. Defines the x, y coordinates of the left-tiptop point of the Bugdroid mascot.
  2. Adds the face's width and height to the left-acme betoken of the face up to calculate the bottom end point's x, y coordinates.
  3. Checks whether the mask's drib location is inside the face bounds. This lets you lot fix an appropriate toast message.
  4. Displays a toast bulletin indicating whether the mask is on the confront or not.

Build and run. You lot'll see the toast message telling yous whether the mask is on or off the face.

Android Drag and Drop Mask

Congratulations! You've now completed the Masky app and learned how to use drag and drop in your Android apps.

Where to Go From Here?

You tin download the completed project files past clicking the Download Materials button at the peak or bottom of the tutorial.

In this tutorial, you learned how to use the Android drag-and-drib framework to motion views and data across views.

Android also supports inter-app drag-and-drop operations. Check the official docs to learn how to take your drag-and-drop skills to the next level.

Want to learn more? Check out our Android Animations video course.

If you have any suggestions or questions, join the give-and-take below.

How To Stop A Click From Being Registered From A Drag Android,

Source: https://www.raywenderlich.com/24508555-android-drag-and-drop-tutorial-moving-views-and-data

Posted by: lambyounts.blogspot.com

0 Response to "How To Stop A Click From Being Registered From A Drag Android"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel