Drag and Drop and OnClick TextView

白昼怎懂夜的黑 提交于 2019-12-24 01:26:31

问题


I'm creating drag and drop text view and I need this text view also can be clicked. My code as per below :

     <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/root"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/bg_grey"
        android:orientation="vertical" >

        <GridView
            android:id="@+id/gridview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:background="@color/bg_grey"
            android:clickable="true"
            android:columnWidth="100dp"
            android:gravity="center"
            android:horizontalSpacing="10dp"
            android:numColumns="2"
            android:stretchMode="columnWidth"
            android:verticalSpacing="10dp" />

        <TextView
            android:id="@+id/drag_drop_button"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:layout_marginLeft="255dp"
            android:layout_marginTop="155dp"
            android:background="@drawable/circle_button"
            android:clickable="true"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:gravity="center"
            android:text="@string/brand"
            android:textColor="@color/sign_blue"
            android:textSize="15sp"
            android:textStyle="bold" />

    </FrameLayout>


class ButtonDragListener implements OnDragListener {
        Drawable normalShape = getResources().getDrawable(
                R.drawable.circle_button);

        @Override
        public boolean onDrag(View v, DragEvent event) {
            int action = event.getAction();
            switch (event.getAction()) {
            case DragEvent.ACTION_DRAG_STARTED:
                // do nothing
                break;
            case DragEvent.ACTION_DRAG_ENTERED:
                // do nothing
                break;
            case DragEvent.ACTION_DRAG_EXITED:
                // do nothing
                break;
            case DragEvent.ACTION_DROP:
                // Dropped, reassign View to ViewGroup
                View view = (View) event.getLocalState();
                view.setX(event.getX());
                view.setY(event.getY());
                ViewGroup owner = (ViewGroup) view.getParent();
                owner.removeView(view);
                FrameLayout container = (FrameLayout) v;
                container.addView(view);
                view.setVisibility(View.VISIBLE);
                break;
            case DragEvent.ACTION_DRAG_ENDED:
                // do nothing
                break;
            default:
                break;
            }
            return true;
        }
    }

        private final class ButtonTouchListener implements OnTouchListener {

            private static final int MAX_CLICK_DURATION = 200;
            private long startClickTime;

            public boolean onTouch(View view, MotionEvent motionEvent) {
                if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
                    startClickTime = Calendar.getInstance().getTimeInMillis();
                    ClipData data = ClipData.newPlainText("", "");
                    DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(
                            view);
                    view.startDrag(data, shadowBuilder, view, 0);
                    view.setVisibility(View.VISIBLE);

                } else if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
                    long clickDuration = Calendar.getInstance().getTimeInMillis()
                            - startClickTime;

                    if (clickDuration < MAX_CLICK_DURATION){ 
                        view.performClick();
                    }
                }
                return true;
            }
        }

        private final class ButtonOnClickListener implements OnClickListener {

            @Override
            public void onClick(View v) {
                Log.e(TAG, "ALOHAAAAA");

            }

        }

        TextView dragDrop = (TextView) view.findViewById(R.id.drag_drop_button);
            dragDrop.setAlpha(0.7f);
            dragDrop.setOnClickListener(new ButtonOnClickListener());
            dragDrop.setOnTouchListener(new ButtonTouchListener());
        frameLayout = (FrameLayout) view.findViewById(R.id.root);
        frameLayout.setOnDragListener(new ButtonDragListener());

But MotionEvent.ACTION_UP never be called, I'm also trying to move view.performClick() inside MotionEvent_ACTION_DOWN, the click listener calling fine but whenever I'm dragging the text view the click listener also run. I also have setOnTouchListener and setOnClickListener directly from textView but the result is same.

What I need here is smooth drag and drop and also click function. Kindly advise what I'm doing wrong here. Thank you and really appreciate for any kind help.


回答1:


I have the same problem as you, your solution is not quite helping me, so I came up with this solution, it's based on your previous solution.

    @Override
    public boolean onTouch(View v, MotionEvent event) {

        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            if (Math.abs(event.getX() - mX) < MAX_X_MOVE || Math.abs(event.getY() - mY) < MAX_Y_MOVE) {
                v.performClick();
            } else {
                ClipData clipData = ClipData.newPlainText("", "");
                View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(v);
                v.startDrag(clipData, shadowBuilder, v, 0);
                v.setVisibility(View.INVISIBLE);

                mX = event.getX();
                mY = event.getY();
            }

            return true;
        }
        return false;
    }



回答2:


This is a kind of a problem where although there is provided solutions, but also you have to think of how these solutions will fit your needs. For my case I used the ideas above and came up with my own solution that fits my needs.

  /**
   * Max value of X to move before we declare that we are going to do
   * drag. 
   */
   private static final float MAX_X_MOVE = 120;

  /**
   * Max value of Y to move before we declare that we are going to do 
   * drag.
   */
   private static final float MAX_Y_MOVE = 120;

   private final static int NONE = 0;

   private final static int DRAG = 1;

   private int m_mode = NONE;

   icon.setOnTouchListener(new View.OnTouchListener() {
     @Override
     public boolean onTouch(View v, MotionEvent event) {

        final int action = event.getAction();

         switch (action){
           case MotionEvent.ACTION_DOWN:
            m_mode = NONE;
           break;

           case MotionEvent.ACTION_MOVE:
             if (Math.abs(event.getX()) > MAX_X_MOVE || 
                 Math.abs(event.getY()) > MAX_Y_MOVE) {
                 m_mode = DRAG;
                 _startDragOnFling();
             }
           break;

           case MotionEvent.ACTION_UP:
              if(m_mode == DRAG){
               break;
              }
              v.performClick();
           break;
         }

        return true;
      }
   });



回答3:


I have solutions for my own problem, I modified my class ButtonTouchListener as per below :

    private final class ButtonTouchListener implements OnTouchListener {

    private static final float MAX_X_MOVE = 70;
    private static final float MAX_Y_MOVE = 70;

    public boolean onTouch(View view, MotionEvent motionEvent) {
        if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
            ClipData data = ClipData.newPlainText("", "");
            DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(
                    view);
            view.startDrag(data, shadowBuilder, view, 0);
            view.setVisibility(View.VISIBLE);

             float offset_x = motionEvent.getX(); 
             float offset_y = motionEvent.getY();


                Log.d(TAG,"OFFSET X = "+offset_x); 
                Log.d(TAG,"OFFSET Y = "+offset_y); 


                if (offset_x < MAX_X_MOVE && offset_y < MAX_Y_MOVE) { 
                    Log.d(TAG,"Here we go"); 
                    view.performClick(); 
                    }


            return true;

        } else {
            return false;
        }

    }

}

Notice that I'm getting pointer x and y from event, this help me to indicate whether the TextView is moving too far, if it move than MAX_X_MOVE and MAX_Y_MOVE will be consider as a drag motion. Maybe it can help others who faced same problem. Any better solution please welcome :)




回答4:


Its already posted for drag Listener and you can write for textView setonClickListener method..

Here is the link..

How to drag the TextView to the correct target other TextView

For onClick..

textView.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            // your code

        }
    });



回答5:


its just an idea, set onClick for the textview in the XML, and call the onClick method as well.

android:onClick="onClickTextView"
public void onClickTextView()

{
// your actions
}



回答6:


Try this, just an idea. Hopefully work for you.

TextView dragDrop = (TextView) view.findViewById(R.id.drag_drop_button);
dragDrop.setAlpha(0.7f);
dragDrop.setOnClickListener(new View.OnClickListener() {

                    @Override
                    public void onClick(View arg0) {
                        // TODO Auto-generated method stub

                    }
                });



回答7:


In my application, a series of buttons can be clicked or dragged. To achieve this I have

  • defined the buttons in XML with the "onClick" attribute referencing a method in my main activity (in your application, attach a "View.OnClickListener" to your TextView instead)
  • defined an "OnDragListener" (it just returns true because all drag events are handled in a separate "OnDragListener" attached to the target View of the drop)
  • defined an "OnLongClickListener"
  • overridden the "onClick()" in my main activity (I can not remember where this is documented)
  • assigned the "OnLongClickListener" to the buttons
  • assigned the "OnDragListener" to the buttons

This is my implementation:

@Override
public void onClick(View v) {  }

class ScDragListenerForButton implements OnDragListener {
    @Override
    public boolean onDrag(View v, DragEvent event) {
        return true;
    }
}

ScDragListenerForButton mDragListenerForButton = new ScDragListenerForButton();

View.OnLongClickListener onLongClickListener = new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View v) {
        Button b = (Button) v;
        ClipData.Item item = new ClipData.Item(b.getText());
        String[] mimeTypes = {ClipDescription.MIMETYPE_TEXT_PLAIN};

        ClipData dragData = new ClipData(b.getText(), mimeTypes, item);
        View.DragShadowBuilder myShadow = new View.DragShadowBuilder(v);

        if (Build.VERSION.SDK_INT < VERSION_CODES.N) {
            v.startDrag(dragData, myShadow, null, 0);
        } else {
            v.startDragAndDrop(dragData, myShadow, null, 0);
        }
        return true;
    }
};

button1.setOnLongClickListener(onLongClickListener);
button1.setOnDragListener(mDragListenerForButton);



回答8:


Try this:

public class MainActivity extends AppCompatActivity implements View.OnTouchListener {
  float dX;
  float dY;
  int lastAction;

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

    final View dragView = findViewById(R.id.draggable_view);
    dragView.setOnTouchListener(this);
  }

  @Override
  public boolean onTouch(View view, MotionEvent event) {
    switch (event.getActionMasked()) {
      case MotionEvent.ACTION_DOWN:
        dX = view.getX() - event.getRawX();
        dY = view.getY() - event.getRawY();
        lastAction = MotionEvent.ACTION_DOWN;
        break;

      case MotionEvent.ACTION_MOVE:
        view.setY(event.getRawY() + dY);
        view.setX(event.getRawX() + dX);
        lastAction = MotionEvent.ACTION_MOVE;
        break;

      case MotionEvent.ACTION_UP:
        if (lastAction == MotionEvent.ACTION_DOWN)
          Toast.makeText(DraggableView.this, "Clicked!", Toast.LENGTH_SHORT).show();
        break;

      default:
        return false;
    }
    return true;
  }
}

And the XML:

<ImageButton
        android:id="@+id/draggable_view"
        android:background="@mipmap/ic_launcher"
        android:layout_gravity="bottom|right"
        android:layout_marginBottom="20dp"
        android:layout_marginEnd="20dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

You can make any View Draggable and Clickable.




回答9:


Try this:

        public class MainActivity extends AppCompatActivity implements View.OnTouchListener, View.OnDragListener , View.OnClickListener {

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

            final View dragView = findViewById(R.id.draggable_view);
            dragView.setOnTouchListener(this);
            dragView.setOnclickListener(this);

          }

     @Override
        public boolean onTouch(View v, MotionEvent event) {

            //if move detected it start Drag event and it's handler or click wil be handled by click listener
            if(event.getAction()  == MotionEvent.ACTION_MOVE){
                View.DragShadowBuilder mShadow = new View.DragShadowBuilder(v);

                    dragView = v;
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                        v.startDragAndDrop(null, mShadow, null, 0);
                    } else {
                        v.startDrag(null, mShadow, null, 0);
                    }
                 }
       return false;
    }

 @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.draggable_view:{
                showToast("click detected");
            }
            break;
           }
       }
}


来源:https://stackoverflow.com/questions/20628202/drag-and-drop-and-onclick-textview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!