How do I restrict drag and drop along the y axis only in android?
NickName:Dog Tamer Ask DateTime:2013-12-01T08:14:54

How do I restrict drag and drop along the y axis only in android?

I'm trying to restrict drag and drop motion to only the Y-axis so that a user can only take a view and drag it up or down--not left or right.

I've got two views (ids of textView and dropZone) right now. One (textView) has a touch listener set to it and another (dropZone) has a drag listener set on it.

Here's the layout xml (activity_main.xml):

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

<TextView
    android:id="@+id/textView"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="50dp"
    android:background="#FFFFFF00"
    android:text="Text Drag" />

<TextView
    android:id="@+id/dropZone"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="167dp"
    android:background="#FFFF0000"
    android:text="Drop Zone" />

</RelativeLayout>

The following is the activity code:

package com.example.dragexperiment;

import android.app.Activity;
import android.content.ClipData;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.DragEvent;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.DragShadowBuilder;
import android.view.View.OnDragListener;
import android.view.View.OnGenericMotionListener;
import android.view.View.OnTouchListener;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class MainActivity extends Activity {
TextView tv, dz, sv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tv = (TextView) findViewById(R.id.textView);
        dz = (TextView) findViewById(R.id.dropZone);
        tv.setOnTouchListener(new MyTouchListener());
        dz.setOnDragListener(new MyDragListener());
    }

    private final class MyTouchListener implements OnTouchListener {
        int viewX0, viewY0,
            cY0, cY1,
            deltaCursorY;

        @Override
        public boolean onTouch(final View v,final MotionEvent event) {
              switch(event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    viewX0 = (int) v.getX();
                    viewY0 = (int) v.getY();
                    cY0 = (int) event.getRawY();
                    ClipData data = ClipData.newPlainText("", "");
                    DragShadowBuilder shadow = new View.DragShadowBuilder(v);
                    v.startDrag(data, shadow, v, 0);
                    return true;
                case MotionEvent.ACTION_MOVE:
                //  cY1 = (int) event.getRawY();
                //  deltaCursorY = cY1 - cY0;
                //  v.setX(viewX0);
                //  v.setY(viewY0 + deltaCursorY);
                    return true;
              }
              return false;
        }
    }

    class MyDragListener implements OnDragListener {

        public boolean onDrag(View v, DragEvent event) {
            switch (event.getAction()) {
            case DragEvent.ACTION_DRAG_STARTED:
                break;
            case DragEvent.ACTION_DRAG_ENTERED:
                v.setBackgroundColor(Color.BLUE);
                break;
            case DragEvent.ACTION_DRAG_EXITED:
                break;
            case DragEvent.ACTION_DROP:
                v.setBackgroundColor(Color.BLUE);
                break;
            case DragEvent.ACTION_DRAG_ENDED:
                break;
            default:
                break;
            }
            return true;
        }
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}

As you can see from the code above, when a user drags textView over dropZone, I try to turn the dropZone view background color to blue. This works fine if I use create a DragShadowBuilder in the ACTION_DOWN motion event:

    ClipData data = ClipData.newPlainText("", "");
    DragShadowBuilder shadow = new View.DragShadowBuilder(v);
    v.startDrag(data, shadow, v, 0);

The problem is that I can't control the shadow so that it only moves along the Y-axis (vertical) axis.

If I take out the DragShadowBuilder code (the three lines above), and add in code to move the dragged view in the ACTION_MOVE motion event (it's commented out above):

    cY1 = (int) event.getRawY();
    deltaCursorY = cY1 - cY0;
    v.setX(viewX0);
    v.setY(viewY0 + deltaCursorY);

Then I can control the textView to move only along the Y-axis. Unfortunately, without a DragShadowBuilder, I can't get the ACTION_DRAG_ENTERED DragEvent to trigger to turn the dropZone view blue.

If I leave both the DragShadowBuilder code and the four lines of code above, the ACTION_MOVE motion event is only triggered once for a drag; it doesn't continue to follow the drag around.

Anybody have any ideas as to what I can do? I've been tooling around with this for a while, but with no luck. I even tried at one point to create a custom view that extends the Android View class, but I can't override the startDrag method because it's declared as final. I wish I were better at this. :(

Copyright Notice:Content Author:「Dog Tamer」,Reproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/20307246/how-do-i-restrict-drag-and-drop-along-the-y-axis-only-in-android

Answers
Ben Chen 2014-04-10T03:38:21

Ah ha! I wasn't able to find this answer anywhere (and a lot of people were asking), so here's what I did.\n\nThe basic idea was to make the DragShadow invisible and pass the Y axis movement to the view you want to \"drag\". So in reality, you're dragging the DragShadow, but it will appear to the user that the draggable view is moving.\n\ndraggableItem.setOnTouchListener(new View.OnTouchListener() {\n @Override\n public boolean onTouch(final View view, MotionEvent motionEvent) {\n if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {\n ClipData data = ClipData.newPlainText(\"\", \"\");\n View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(new View(getApplicationContext()));\n view.startDrag(data, shadowBuilder, view, 0);\n return true;\n } else {\n return false;\n }\n }\n });\n\nmDropZone.setOnDragListener(new View.OnDragListener() {\n @Override\n public boolean onDrag(View v, DragEvent event) {\n switch (event.getAction()) {\n case DragEvent.ACTION_DRAG_STARTED:\n ViewGroup.MarginLayoutParams lParams = (ViewGroup.MarginLayoutParams) arcMenu.getLayoutParams();\n _yDelta = (int) event.getY() - lParams.topMargin;\n break;\n case DragEvent.ACTION_DRAG_LOCATION:\n ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) arcMenu.getLayoutParams();\n layoutParams.topMargin = (int) event.getY() - _yDelta;\n arcMenu.setLayoutParams(layoutParams);\n break;\n case DragEvent.ACTION_DROP:\n // Dropped, reassign View to ViewGroup\n View view = (View) event.getLocalState();\n\n // Do your drop actions here\n\n view.setVisibility(View.VISIBLE);\n break;\n default:\n break;\n }\n return true;\n }\n });\n\n\nYou'll also need to declare the _yDelta variable in your class. \n\nHope this works for all you cool cats out there! ",


More about “How do I restrict drag and drop along the y axis only in android?” related questions

How do I restrict drag and drop along the y axis only in android?

I'm trying to restrict drag and drop motion to only the Y-axis so that a user can only take a view and drag it up or down--not left or right. I've got two views (ids of textView and dropZone) righ...

Show Detail

Drag & drop in Android with only Y axis movement?

Referring to https://developer.android.com/guide/topics/ui/drag-drop, is there a way to somehow "freeze" x position of a drag shadow so it will only move up or down?

Show Detail

Android 4 Drag & Drop horizontally

I am able to drag n drop items successfully with View.startDrag method. But I want to restrict dragging only by X axis with some Y axis offset. Currently when user started dragging he is able to m...

Show Detail

Restrict drag only in one direction

Using jQuery Draggable How to restrict a draggable to be dragged only in one direction ? i.e either only top or only bottom when axis: 'y' and either only left or only right when axis: 'x' This ...

Show Detail

Android - Rotate Object along Y-Axis

I've a TextView in my app and I want it to rotate from left edge along Y-Axis. Using this code, &lt;rotate android:fromDegrees="90" android:toDegrees="0" android:pivotX="0%"

Show Detail

How to drag SCNNode along specific axis after rotation?

I am currently working on Swift ARKit project. I am trying to figure out how can I drag node object at specific axis even after some rotations. For example I want to move node along Y axis after

Show Detail

Restrict drag/drop for a node in jQuery?

can somebody please tell how to use this solution to solve my problem. I too want to restrict drag/drop for a node whose id has text "not" in it. jsTree drag and drop restrict folders by class he...

Show Detail

How to drag a view ONLY on y-axis?

I want to create a dragable view which is only dragable on the Y-Axis. Normally i would use a DragShadow and would do something like this: @Override public boolean onTouch(View view, MotionEvent

Show Detail

How to restrict the drag and drop area in a canvas

I have a canvas,lets say of dimensions 500x600.I have some controls inside that canvas.User can rearrange the controls by drag and drop.But I want to restrict the drag and drop within that canvas....

Show Detail

HTML Input type file to support only drag and drop but restrict file browse and upload

I have input type "file". &lt;input type="file" class="someCssClass" (drop)="onImageDrop($event)" required&gt; I want to restrict user so that they can't click on the file

Show Detail